题解 SP1557 GSS2 - Can you answer these queries II

· · 题解

由于每个相同的数只能出现一次,是一个经典的扫描线问题的暗示。

考虑扫描线,扫描 r 维对每个位置 l 维护区间 [l,r] 中要求下的和。

显然维护每个数的 lst,我们只需要对于区间 [lst_r + 1 , r] 进行区间加。

同时维护每个区间的历史最大值即可维护答案。

#include "bits/stdc++.h"
using namespace std;
const int Len = 5e5 + 5 , Inf = 1e9;
int n,m,a[Len];
#define ls(p) p << 1
#define rs(p) p << 1 | 1
struct node
{
    long long sum;
    int maxa,maxb,se,cnt;
    int add_a,add_a1,add_b,add_b1;//最大值的 tag,max 的上一次到这一次的 maxtag,其它值的 tag,其它数这一次到上一次的 maxtag 
}t[Len << 2];
inline int read() {
    char ch = getchar();
    int x = 0, f = 1;
    while (ch < '0' || ch > '9') {
        if (ch == '-')
            f = -1;
        ch = getchar();
    }
    while ('0' <= ch && ch <= '9') {
        x = x * 10 + ch - '0';
        ch = getchar();
    }
    return x * f;
}
inline void write(long long x) {
    if (x < 0)
        putchar('-'), x = -x;
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void push_up(int x)
{
    t[x].sum = t[ls(x)].sum + t[rs(x)].sum;
    t[x].maxa = max(t[ls(x)].maxa , t[rs(x)].maxa);
    t[x].maxb = max(t[ls(x)].maxb , t[rs(x)].maxb);
    if(t[ls(x)].maxa == t[rs(x)].maxa)
    {
        t[x].se = max(t[ls(x)].se , t[rs(x)].se);
        t[x].cnt = t[ls(x)].cnt + t[rs(x)].cnt;
    }
    if(t[ls(x)].maxa > t[rs(x)].maxa)
    {
        t[x].se = max(t[rs(x)].maxa , t[ls(x)].se);
        t[x].cnt = t[ls(x)].cnt;
    }
    if(t[ls(x)].maxa < t[rs(x)].maxa)
    {
        t[x].se = max(t[ls(x)].maxa , t[rs(x)].se);
        t[x].cnt = t[rs(x)].cnt;
    }
}
void upd(int p,int l,int r,int k1,int k2,int k3,int k4)
{
    t[p].sum += (1ll * t[p].cnt * k1 + 1ll * (r - l + 1 - t[p].cnt) * k3);
    t[p].maxb = max(t[p].maxb , t[p].maxa + k2);
    t[p].add_b = max(t[p].add_b , t[p].add_a + k2);
    t[p].add_b1 = max(t[p].add_b1 , t[p].add_a1 + k4);
    t[p].maxa += k1 , t[p].add_a += k1;
    t[p].add_a1 += k3;
    if(t[p].se != -Inf) t[p].se += k3;
}
void push_down(int p,int l,int r)
{
    if(t[p].add_a == 0 && t[p].add_a1 == 0 && t[p].add_b == 0 && t[p].add_b1 == 0) return;
    int maxa = max(t[ls(p)].maxa , t[rs(p)].maxa) , mid = (l + r) >> 1;
    if(t[ls(p)].maxa == maxa) upd(ls(p) , l , mid , t[p].add_a , t[p].add_b , t[p].add_a1 , t[p].add_b1);
    else upd(ls(p) , l , mid , t[p].add_a1 , t[p].add_b1 , t[p].add_a1 , t[p].add_b1);
    if(t[rs(p)].maxa == maxa) upd(rs(p) , mid + 1 , r , t[p].add_a , t[p].add_b , t[p].add_a1 , t[p].add_b1);
    else upd(rs(p) , mid + 1 , r , t[p].add_a1 , t[p].add_b1 , t[p].add_a1 , t[p].add_b1);
    t[p].add_a = t[p].add_b = t[p].add_a1 = t[p].add_b1 = 0;
}
void build(int p,int l,int r)
{
    t[p].add_a = t[p].add_b = t[p].add_a1 = t[p].add_b1 = 0;
    if(l == r) 
    {
        t[p].maxa = t[p].maxb = t[p].sum = a[l] , t[p].se = -Inf , t[p].cnt = 1;
        return;
    }
    int mid = (l + r) >> 1;
    build(ls(p) , l , mid);
    build(rs(p) , mid + 1 , r);
    push_up(p);
}
void Add(int p,int l,int r,int nl,int nr,int w)
{
    if(nl <= l && nr >= r) 
    {
        upd(p , l , r , w , w , w , w);
        return;
    }
    push_down(p , l , r);
    int mid = (l + r) >> 1;
    if(nl <= mid) Add(ls(p) , l , mid , nl , nr , w);
    if(nr > mid) Add(rs(p) , mid + 1 , r , nl , nr , w);
    push_up(p);
}
void updmin(int p,int l,int r,int nl,int nr,int w)
{
    if(w >= t[p].maxa) return;
    if(nl <= l && nr >= r && w >= t[p].se) 
    {
        upd(p , l , r , w - t[p].maxa , w - t[p].maxa , 0 , 0);
        return;
    }
    push_down(p , l , r);
    int mid = (l + r) >> 1;
    if(nl <= mid) updmin(ls(p) , l , mid , nl , nr , w);
    if(nr > mid) updmin(rs(p) , mid + 1 , r , nl , nr , w);
    push_up(p);
}
long long query(int p,int l,int r,int nl,int nr)
{
    //printf("!!!%d %d %d\n",p,l,r);
    if(nl <= l && nr >= r) return t[p].sum;
    push_down(p , l , r);
    int mid = (l + r) >> 1;long long res = 0;
    if(nl <= mid) res += query(ls(p) , l , mid , nl , nr);
    if(nr > mid) res += query(rs(p) , mid + 1 , r , nl , nr);
    return res;
}
int qmaxa(int p,int l,int r,int nl,int nr)
{
    if(nl <= l && nr >= r) return t[p].maxa;
    push_down(p , l , r);
    int mid = (l + r) >> 1 , res = -Inf;
    if(nl <= mid) res = max(res , qmaxa(ls(p) , l , mid , nl , nr));
    if(nr > mid) res = max(res , qmaxa(rs(p) , mid + 1 , r , nl , nr));
    return res;
}
int qmaxb(int p,int l,int r,int nl,int nr)
{
    if(nl <= l && nr >= r) return t[p].maxb;
    push_down(p , l , r);
    int mid = (l + r) >> 1 , res = -Inf;
    if(nl <= mid) res = max(res , qmaxb(ls(p) , l , mid , nl , nr));
    if(nr > mid) res = max(res , qmaxb(rs(p) , mid + 1 , r , nl , nr));
    return res;
}
int main()
{
    n = read() , m = read();
    for(int i = 1 ; i <= n ; i ++) a[i] = read();
    build(1 , 1 , n);
    //puts("YES");
    for(int i = 1 ; i <= m ; i ++)
    {
        int opt;opt = read();
        int l,r,k;l = read() , r = read();
        if(opt == 1){k = read();Add(1 , 1 , n , l , r , k);}
        else if(opt == 2){k = read();updmin(1 , 1 , n , l , r , k);}
        else if(opt == 3){write(query(1 , 1 , n , l , r));puts("");}
        else if(opt == 4){write(qmaxa(1 , 1 , n , l , r));puts("");}
        else{write(qmaxb(1 , 1 , n , l , r));puts("");}
    }
    return 0;
}