BZOJ1500: [NOI2005]维修数列 && SPOJ-GSS6 【Splay】

本文详细记录了作者攻克一道涉及Splay树数据结构难题的过程,包括调试经历与心得,最终成功解决问题并分享了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

早已膜拜过这等数据结构神题。一直没下定决心做。于是今天终于下定决心要把它A掉。

 

14:39 我要把这道题搞出来!

以前看到这道题的时候一直纠结建树的时候都是按下标建的。可是现在中间会插入删除,下标没法存了肿么破。

结果其实从根下去根据size找第几个就行了。真是太弱了。然后就可做了。

 

15:38 程序码完了..不管怎样编译过了。虽然样例还没试。但是很激动的赶脚。

15:39 开始调试样例。调了几下欣喜若狂以为对了。(我竟然没发现有一个输出是1我输出的是0)

15:59 我激动的交上OJ,结果是T?!

然后是各种对拍。各种输出。各种眼花。各种绝望。

 

17:32 改了改,还是T?!

然后就是一直一直不停的调。。始终发现不了问题在哪。。

 

18:09 从szy大神那要来了数据。感谢。(是的我调了这么久了)

然后我发现除了第一个点后面都T了。受不了了。我写的splay这么渣?

 

后来绝望了就先去吃饭了。

 

20:21 回来继续调,发现了从根降下去的时候没有pushdown!

改过来有90分了!其实我本来想交上OJ的。因为自己机子本身就不快,交到OJ上应该可以A的。

不过想想还是加了个读入优化。果然,轻松100。

 

于是——

真是各种兴奋。

从开始写到正式A掉花了六个小时。调的时间比写的时间多多了。唉真是弱逼。

不过终于把这道神题A掉了。算是对自己的平衡树学习的一个交代吧。

 

写的过程中发现了几处要注意的地方:

1.从根下降的时候要先pushdown。。唉真是太弱了。。T.T这都会忘。。那么久还没发现。。

2.求最大连续子串和的时候,初始max要置为-inf而不是0。因为有可能答案就是负数。这点在GSS系列中曾经吃过苦头>.<

3.开个垃圾回收吧。不然有可能爆内存的说。(虽然我没试过D)

4.区分这几个操作的单词时。可以比较它们第3个字母。发现它们是各不相同的。呵呵。不过想怎么弄就怎么弄。呵呵。

 

贴上代码。我会说这是我写到现在为止最长的一个程序?(Q:你煞笔吧。这就最长了?A:我的确是煞笔。。) 

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

#define maxn 500005
int n,q,a[maxn];

struct SplayTree{
    #define S 500005
    #define inf 100000009
    
    int ch[S][2],fa[S],val[S],sz[S],rev[S],same[S],sum[S],lmax[S],rmax[S],smax[S],pool[S],rt,tot,poolcnt;
    
    #define ls ch[x][0]
    #define rs ch[x][1]
    #define key ch[ch[rt][1]][0]
    #define SPLAY rto(pos,0);rto(pos+k+1,rt)
    
    inline void sw(int &a,int &b){  a^=b;   b^=a;   a^=b;   }
    
    inline void newnode(int &x,int k,int f){
        if(poolcnt) x=pool[poolcnt--];  else x=++tot;
        ls=rs=rev[x]=same[x]=0;
        fa[x]=f;sz[x]=1;
        val[x]=sum[x]=lmax[x]=rmax[x]=smax[x]=k;
    }
    
    inline void rotate(int x,int f){
        int y=fa[x];
        pushdown(y);
        pushdown(x);
        ch[y][!f]=ch[x][f];
        fa[ch[x][f]]=y;
        if(fa[y])   ch[fa[y]][ch[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        ch[x][f]=y;
        fa[y]=x;
        pushup(y);
    }
    
    inline void splay(int x,int goal){
        pushdown(x);
        while(fa[x]!=goal){
            if(fa[fa[x]]==goal) rotate(x,ch[fa[x]][0]==x);
            else{
                int y=fa[x],z=fa[y];
                int f=(ch[z][0]==y);
                if(ch[y][f]==x) rotate(x,!f),rotate(x,f);
                else    rotate(y,f),rotate(x,f);
            }
        }
        pushup(x);
        if(goal==0)rt=x;
    }
    
    inline void rto(int k,int goal){
        int x=rt;
        pushdown(x);
        while(sz[ls]+1!=k){
            if(k<sz[ls]+1)    x=ls;
            else    k-=(sz[ls]+1),x=rs;
            pushdown(x);
        }
        splay(x,goal);
    }
    
    inline void updsame(int x,int v){
        if(!x)  return;
        same[x]=1;
        val[x]=v;
        sum[x]=sz[x]*v;
        lmax[x]=rmax[x]=smax[x]=max(v,v*sz[x]);
    }
    
    inline void updrev(int x){
        if(!x)  return;
        sw(ls,rs);  sw(lmax[x],rmax[x]);
        rev[x]^=1;
    }
    
    inline void pushup(int x){
        sz[x]=sz[ls]+sz[rs]+1;
        sum[x]=sum[ls]+sum[rs]+val[x];
        lmax[x]=max(lmax[ls],sum[ls]+val[x]+max(0,lmax[rs]));
        rmax[x]=max(rmax[rs],sum[rs]+val[x]+max(0,rmax[ls]));
        smax[x]=max(max(smax[ls],smax[rs]),max(0,rmax[ls])+val[x]+max(0,lmax[rs]));
    }
    
    inline void pushdown(int x){
        if(rev[x])  updrev(ls),updrev(rs),rev[x]=0;
        if(same[x]) updsame(ls,val[x]),updsame(rs,val[x]),same[x]=0;
    }
    
    inline void build(int &x,int l,int r,int f){
        if(l>r) return;
        int mid=(l+r)>>1;
        newnode(x,a[mid],f);
        build(ls,l,mid-1,x);
        build(rs,mid+1,r,x);
        pushup(x);
    }
    
    inline void init(){
        tot=poolcnt=rt=0;
        ch[rt][0]=ch[rt][1]=fa[rt]=rev[rt]=same[rt]=sz[rt]=sum[rt]=0;
        lmax[rt]=rmax[rt]=smax[rt]=-inf;
        newnode(rt,-1,0);   
        newnode(ch[rt][1],-1,rt);
        pushup(rt); 
        build(key,1,n,ch[rt][1]);
        pushup(ch[rt][1]);  
        pushup(rt);
    }
    
    inline int getnum(int k){
        int x=rt;
        pushdown(x);
        while(sz[ls]+1!=k){
            if(k<sz[ls]+1)  x=ls;
            else    k-=(sz[ls]+1),x=rs;
            pushdown(x);
        }
        return x;
    }
    
    inline int getmin(int x){
        pushdown(x);
        while(ls)   x=ls,pushdown(x);
        return x;
    }
    
    inline void ins(int pos,int k){
        int x=getnum(pos);
        splay(x,0);
        int m=getmin(ch[rt][1]);
        splay(m,rt);
        build(key,1,k,ch[rt][1]);
        pushup(ch[rt][1]);
        pushup(rt);
    }
    
    inline void delone(int x){
        if(!x)  return;
        pool[++poolcnt]=x;
        delone(ls); delone(rs);
    }
    
    inline void del(int pos,int k){
        SPLAY;
        delone(key);
        fa[key]=0;
        key=0;
        pushup(ch[rt][1]);
        pushup(rt);
    }
    
    inline void makesame(int pos,int k,int v){
        SPLAY;
        updsame(key,v);
        pushup(ch[rt][1]);
        pushup(rt);
    }
    
    inline void reverse(int pos,int k){ 
        SPLAY;
        updrev(key);
    }
    
    inline int getsum(int pos,int k){   
        SPLAY;
        return sum[key];    
    }
    
    inline int _getmaxsum(int pos,int k){
        SPLAY;
        return smax[key];   
    }
    
    inline int getmaxsum(void){
        return _getmaxsum(1,sz[rt]-2);
    }
}spt;

inline void read(int &x){
    char ch;    int f=1;
    for(ch=getchar();(ch<'0' || ch>'9')&&(ch!='-');ch=getchar());
    if(ch=='-')f=-1,x=0;    else x=ch-'0';
    for(ch=getchar();ch>='0' && ch<='9';ch=getchar())x=x*10+ch-'0';
    x*=f;
}

int main()
{
    //freopen("sequence.in","r",stdin);
    //freopen("sequence.out","w",stdout);
    read(n);    read(q);
    for(int i=1;i<=n;i++)   read(a[i]);
    spt.init();
    char op[10];
    int pos,k,v;
    while(q--){
        scanf("%s",op);
        if(op[2]=='S'){
            read(pos);  read(k);
            for(int i=1;i<=k;i++)   read(a[i]);
            spt.ins(pos+1,k);
        }else if(op[2]=='L'){
            read(pos);  read(k);
            spt.del(pos,k);
        }else if(op[2]=='K'){
            read(pos);  read(k);    read(v);
            spt.makesame(pos,k,v);
        }else if(op[2]=='V'){
            read(pos);  read(k);
            spt.reverse(pos,k);
        }else if(op[2]=='T'){
            read(pos);  read(k);
            printf("%d\n",spt.getsum(pos,k));
        }else printf("%d\n",spt.getmaxsum());
    }
    return 0;
}

 

做完这题就可以把GSS6(要求支持操作:插入一个数、删除一个数、修改一个数、询问最大连续子段和)轻松A掉了。虽然我A的很不轻松。我竟然没发现newnode的时候size没设成1。= =真是奇葩。这道题一开始我也没写但是却过了。于是现在我把这句加上了。

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;

#define maxn 300005
int n,q,a[maxn];

struct SplayTree{
    #define S 300005
    #define inf 100000009
    
    int ch[S][2],fa[S],val[S],sz[S],sum[S],lmax[S],rmax[S],smax[S],pool[S],rt,tot,poolcnt;
    
    #define ls ch[x][0]
    #define rs ch[x][1]
    #define key ch[ch[rt][1]][0]
    
    inline void sw(int &a,int &b){  a^=b;   b^=a;   a^=b;   }
    
    inline void newnode(int &x,int k,int f){
        if(poolcnt) x=pool[poolcnt--];  else x=++tot;
        sz[x]=1;
        ls=rs=0;
        fa[x]=f;
        val[x]=sum[x]=lmax[x]=rmax[x]=smax[x]=k;
    }
    
    inline void rotate(int x,int f){
        int y=fa[x];
        ch[y][!f]=ch[x][f];
        fa[ch[x][f]]=y;
        if(fa[y])   ch[fa[y]][ch[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        ch[x][f]=y;
        fa[y]=x;
        pushup(y);
    }
    
    inline void splay(int x,int goal){
        while(fa[x]!=goal){
            if(fa[fa[x]]==goal) rotate(x,ch[fa[x]][0]==x);
            else{
                int y=fa[x],z=fa[y];
                int f=(ch[z][0]==y);
                if(ch[y][f]==x) rotate(x,!f),rotate(x,f);
                else    rotate(y,f),rotate(x,f);
            }
        }
        pushup(x);
        if(goal==0)rt=x;
    }
    
    inline void rto(int k,int goal){
        int x=rt;
        while(sz[ls]+1!=k){
            if(k<sz[ls]+1)    x=ls;
            else    k-=(sz[ls]+1),x=rs;
        }
        splay(x,goal);
    }
    
    inline void pushup(int x){
        sz[x]=sz[ls]+sz[rs]+1;
        sum[x]=sum[ls]+sum[rs]+val[x];
        lmax[x]=max(lmax[ls],sum[ls]+val[x]+max(0,lmax[rs]));
        rmax[x]=max(rmax[rs],sum[rs]+val[x]+max(0,rmax[ls]));
        smax[x]=max(max(smax[ls],smax[rs]),max(0,rmax[ls])+val[x]+max(0,lmax[rs]));
    }
    
    inline void build(int &x,int l,int r,int f){
        if(l>r) return;
        int mid=(l+r)>>1;
        newnode(x,a[mid],f);
        build(ls,l,mid-1,x);
        build(rs,mid+1,r,x);
        pushup(x);
    }
    
    inline void init(){
        tot=poolcnt=rt=0;
        ch[rt][0]=ch[rt][1]=fa[rt]=sz[rt]=sum[rt]=0;
        lmax[rt]=rmax[rt]=smax[rt]=-inf;
        newnode(rt,-1,0);   
        newnode(ch[rt][1],-1,rt);
        pushup(rt); 
        build(key,1,n,ch[rt][1]);
        pushup(ch[rt][1]);  
        pushup(rt);
    }
    
    inline int getnum(int k){
        int x=rt;
        while(sz[ls]+1!=k){
            if(k<sz[ls]+1)  x=ls;
            else    k-=(sz[ls]+1),x=rs;
        }
        return x;
    }
    
    inline int getmin(int x){
        while(ls)   x=ls;
        return x;
    }
    
    inline void ins(int pos){
        rto(pos,0);
        rto(pos+1,rt);
        newnode(key,a[1],ch[rt][1]);
        pushup(key);
        pushup(ch[rt][1]);
        pushup(rt);
    }
    
    inline void del(int pos){
        rto(pos,0);
        rto(pos+2,rt);
        pool[++poolcnt]=key;
        fa[key]=0;
        key=0;
        pushup(ch[rt][1]);
        pushup(rt);
    }
    inline void change(int pos,int v){
        rto(pos,0);
        rto(pos+2,rt);
        val[key]=v;
        pushup(ch[rt][1]);
        pushup(rt);
        splay(key,0);
    }
    
    inline int getmaxsum(int pos,int k){
        rto(pos,0);
        rto(pos+k+1,rt);
        return smax[key];   
    }
}spt;

inline void read(int &x){
    char ch;    int f=1;
    for(ch=getchar();(ch<'0' || ch>'9')&&(ch!='-');ch=getchar());
    if(ch=='-')f=-1,x=0;    else x=ch-'0';
    for(ch=getchar();ch>='0' && ch<='9';ch=getchar())x=x*10+ch-'0';
    x*=f;
}

int main()
{
    read(n);
    for(int i=1;i<=n;i++)   read(a[i]);
    spt.init();
    char op[2];
    int pos,v;
    read(q);
    while(q--){
        scanf("%s",op);
        if(op[0]=='I'){
            read(pos);  read(a[1]);
            spt.ins(pos);
        }else if(op[0]=='D'){
            read(pos);
            spt.del(pos);
        }else if(op[0]=='R'){
            read(pos);  read(v);
            spt.change(pos,v);
        }else{
            read(pos);  read(v);
            printf("%d\n",spt.getmaxsum(pos,v-pos+1));
        }
    }
    return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值