线段树乱做GSS

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线段树乱做GSS相关的知识,希望对你有一定的参考价值。

线段树乱做GSS

SP1043 GSS1

区间最大子段和,显然可以线段树维护4个变量,左端点开始的答案,右端点结尾的答案,整个区间的答案,整个区间的和。

答案参考题解区

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#define SIZE 50010
#define lson p<<1,l,mid
#define rson p<<1|1,mid+1,r
using namespace std;
int n,m,x,y;
struct SegmentTree{
    int sum,lmax,rmax,dat;
}tr[SIZE<<2];

inline int rin(){
    int f=1,x=0; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-') f=-1; ch=getchar();}
    while(ch<='9'&&ch>='0') x=x*10+ch-'0',ch=getchar();
    return f*x;
}
inline void Update(int p){
    tr[p].sum=tr[p<<1].sum+tr[p<<1|1].sum;
    tr[p].lmax=max(tr[p<<1].lmax,tr[p<<1].sum+tr[p<<1|1].lmax);
    tr[p].rmax=max(tr[p<<1|1].rmax,tr[p<<1|1].sum+tr[p<<1].rmax);
    tr[p].dat=max(max(tr[p<<1].dat,tr[p<<1|1].dat),tr[p<<1].rmax+tr[p<<1|1].lmax);
}
inline void Build(int p,int l,int r){
    if(l==r){tr[p].dat=tr[p].sum=tr[p].lmax=tr[p].rmax=rin(); return;}
    int mid=(l+r)>>1;
    Build(lson); Build(rson);
    Update(p);
}
inline SegmentTree Query(int p,int l,int r,int ql,int qr){
    if(ql<=l&&qr>=r) return tr[p];
    int mid=(l+r)>>1;
    if(ql>mid) return Query(rson,ql,qr);
    if(qr<=mid) return Query(lson,ql,qr);
    else{
        SegmentTree ans,a,b;
        a=Query(lson,ql,qr); b=Query(rson,ql,qr);
        ans.sum=a.sum+b.sum;
        ans.dat=max(a.dat,a.rmax+b.lmax),ans.dat=max(ans.dat,b.dat);
        ans.lmax=max(a.lmax,a.sum+b.lmax);
        ans.rmax=max(b.rmax,b.sum+a.rmax);
        return ans;
    }
}

int main(){
    n=rin();
    Build(1,1,n);
    m=rin();
    for(int i=1;i<=m;i++){
        x=rin(),y=rin();
        printf("%d\\n",Query(1,1,n,x,y).dat);
    }
    
    return 0;
}

SP1557 GSS2

区间最大子段去重和。

考虑离线,预处理每个数上一次出现的位置 p r e [ a i ] pre[a_i] pre[ai]

将询问按右端点排序。

线段树每个结点维护 4 4 4个变量: s u m , h i s s u m , t a g , h i s t a g sum,hissum,tag,histag sum,hissum,tag,histag

当前子段和、历史最大子段和、区间加标记,历史最大区间加标记。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
inline LL read(){
    LL x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int MAXN=100005;
struct Node{
    LL sum,hix,stag,htag;
    Node(){
        sum=hix=stag=htag=0;
    }
    friend Node operator + (Node lf,Node rt){
        Node res;
        res.sum=max(lf.sum,rt.sum);
        res.hix=max(lf.hix,rt.hix);
        return res;
    }
}b[MAXN*4];
struct Qst{
    int l,r,id;
}q[MAXN];
bool cmp(Qst x,Qst y){
    return x.r<y.r;
}
int n,m,cur[MAXN*2],pre[MAXN],ql,qr;LL a[MAXN],ans[MAXN],k;
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc ((o<<1)|1)
void pushup(int o){
    b[o]=b[lc]+b[rc];
}
void pushdown(int o){//注意更新先后顺序 
    b[lc].hix=max(b[lc].hix,b[lc].sum+b[o].htag);
    b[rc].hix=max(b[rc].hix,b[rc].sum+b[o].htag);
    b[lc].sum+=b[o].stag;
    b[rc].sum+=b[o].stag;
    b[lc].htag=max(b[lc].htag,b[lc].stag+b[o].htag);
    b[rc].htag=max(b[rc].htag,b[rc].stag+b[o].htag);
    b[lc].stag+=b[o].stag;
    b[rc].stag+=b[o].stag;
    b[o].stag=b[o].htag=0;
}
void upd(int o,int l,int r){
    if(ql<=l&&r<=qr){
        b[o].sum+=k;
        b[o].hix=max(b[o].hix,b[o].sum);
        b[o].stag+=k;
        b[o].htag=max(b[o].htag,b[o].stag);
        return;
    }
    pushdown(o);
    if(mid>=ql) upd(lc,l,mid);
    if(mid<qr) upd(rc,mid+1,r);
    pushup(o);
}
Node query(int o,int l,int r){
    if(ql<=l&&r<=qr) return b[o];
    pushdown(o);
    if(mid<ql) return query(rc,mid+1,r);
    else if(mid>=qr) return query(lc,l,mid);
    else return query(lc,l,mid)+query(rc,mid+1,r);
}
int main(){
    n=read();
    for(int i=1;i<=n;i++){
        a[i]=read();
        pre[i]=cur[a[i]+(int)1e5];
        cur[a[i]+(int)1e5]=i;
    }
    m=read();
    for(int i=1;i<=m;i++){
        q[i].l=read(),q[i].r=read();
        q[i].id=i;
    }
    sort(q+1,q+m+1,cmp);
    int j=1;
    for(int i=1;i<=n;i++){
        ql=pre[i]+1,qr=i,k=a[i];
        upd(1,1,n);
        for(;j<=m&&q[j].r<=i;j++){
            ql=q[j].l,qr=q[j].r;
            ans[q[j].id]=query(1,1,n).hix;
        }
    }
    for(int i=1;i<=m;i++)
        printf("%lld\\n",ans[i]);
    return 0;
}

逃了,wtcl

以上是关于线段树乱做GSS的主要内容,如果未能解决你的问题,请参考以下文章

树套树乱讲

SPOJ GSS3 Can you answer these queries III ——线段树

SPOJ GSS5 Can you answer these queries V ——线段树

SPOJ1043 GSS1 (线段树)

SPOJ 1043 GSS1 & 1716 GSS3 Can you answer these queries 线段树

SP2713 GSS4 - Can you answer these queries IV(线段树)