#离线,线段树#SP1557 GSS2 - Can you answer these queries II

题目

给定大小为 \(n\) 的序列,\(q\) 次询问,求最大子段和,

相同的数只算一次。选出的子段可以为空。


分析

数字不重复很难做,考虑离线,询问区间按右端点排序

枚举区间右端点,不重复就相当于给 \([pre+1,i]\) 为开头的区间后添加 \(a_i\)

那么相当于维护以 \(j\) 为开头的最大子段和,以及历史最大子段和

那么下放懒标记就要注意次序(先处理历史值再处理当前值)


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=100011; typedef long long lll;
struct rec{int l,r,rk;}q[N];
int n,pre[N<<1],a[N],Q; lll ans[N];
struct Rec{
    lll mx,Mx,lazy,Lazy;
    void ptag(lll tag,lll Tag){
        Mx=max(Mx,mx+Tag),mx+=tag;
        Lazy=max(Lazy,lazy+Tag),lazy+=tag;
    }
}w[N<<2];
int iut(){
    int ans=0,f=1; char c=getchar();
    while (!isdigit(c)) f=(c=='-')?-f:f,c=getchar();
    while (isdigit(c)) ans=ans*10+c-48,c=getchar();
    return ans*f;
}
void print(lll ans){
    if (ans>9) print(ans/10);
    putchar(ans%10+48);
}
bool cmp(rec x,rec y){return x.r<y.r;}
Rec pup(Rec f,Rec g){
    Rec h; h.lazy=h.Lazy=0;
    h.mx=f.mx>g.mx?f.mx:g.mx;
    h.Mx=f.Mx>g.Mx?f.Mx:g.Mx;
    return h;
}
void update(int k,int l,int r,int x,int y,int z){
    if (l==x&&r==y){
        w[k].ptag(z,z);
        return;
    }
    int mid=(l+r)>>1;
    if (w[k].lazy||w[k].Lazy){
        w[k<<1].ptag(w[k].lazy,w[k].Lazy);
        w[k<<1|1].ptag(w[k].lazy,w[k].Lazy);
        w[k].lazy=w[k].Lazy=0;
    }
    if (y<=mid) update(k<<1,l,mid,x,y,z);
    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
    w[k]=pup(w[k<<1],w[k<<1|1]);
}
Rec query(int k,int l,int r,int x,int y){
    if (l==x&&r==y) return w[k];
    int mid=(l+r)>>1;
    if (w[k].lazy||w[k].Lazy){
        w[k<<1].ptag(w[k].lazy,w[k].Lazy);
        w[k<<1|1].ptag(w[k].lazy,w[k].Lazy);
        w[k].lazy=w[k].Lazy=0;
    }
    if (y<=mid) return query(k<<1,l,mid,x,y);
    else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
        else return pup(query(k<<1,l,mid,x,mid),query(k<<1|1,mid+1,r,mid+1,y));
}
int main(){
    n=iut();
    for (int i=1;i<=n;++i) a[i]=iut();
    Q=iut();
    for (int i=1;i<=Q;++i) q[i]=(rec){iut(),iut(),i};
    sort(q+1,q+1+Q,cmp);
    for (int i=1,j=1;i<=Q;++i){
        for (;j<=q[i].r;++j){
            update(1,1,n,pre[a[j]+100000]+1,j,a[j]);
            pre[a[j]+100000]=j;
        }
        ans[q[i].rk]=query(1,1,n,q[i].l,q[i].r).Mx;
    }
    for (int i=1;i<=Q;++i) print(ans[i]),putchar(10);
    return 0;
}
posted @ 2024-04-05 22:56  lemondinosaur  阅读(3)  评论(0编辑  收藏  举报