NOI2005维护数列 伸展树splay

来源:互联网 发布:鲍里斯三世知乎 编辑:程序博客网 时间:2024/05/21 14:52

        7K的代码....从中午调到现在...终于调过去了.....太感动了.....

        中文的题目题意就不多说了...前五个操作都是最基本的splay操作,最后一个稍微麻烦点,可以先去做做http://blog.csdn.net/yanglei040/article/details/12625039这个题..要求某个区间的最大子段和的话,对于每个区间,要维护区间和sum,区间最大后缀suff,最大前缀pref,最大子段和sub四个值,因为在pushup的时候,sub可以是他两个子区间的sub的最大值,也可能是左孩子的suff+自己的值+右孩子的pref,前缀和后缀的更新方式也基本类似了,然后...就没有然后了..慢慢调吧,耐心调早晚能调出来的...另外有一点要注意的就是make-same操作要用两个值维护,setn表示改成多少,same表示是否有标记。因为他的数据可能有make-same x y 0的情况,如果要用setn去表示是否标记的话,搞不好就要WA到哭了,我大部分时间都坑在这里了....先贴一个没加任何优化的代码..

#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=4000000+4000;int pre[maxn],ch[maxn][2];int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{    void pushup(int r)    {        if (r==0) return;        size[r]=size[ch[r][0]]+1+size[ch[r][1]];        sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]];        pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]]));        suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]]));        sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]);        sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]]));    }    void rotate(int x,int kind)    {        int y=pre[x];        pushdown(y);        pushdown(x);        ch[y][!kind]=ch[x][kind];        pre[ch[x][kind]]=y;        if (pre[y])        {            ch[pre[y]][ch[pre[y]][1]==y]=x;        }        pre[x]=pre[y];        ch[x][kind]=y;        pre[y]=x;        pushup(y);        pushup(x);    }    void splay(int x,int tgt)    {        pushdown(x);        while(pre[x]!=tgt)        {            int y=pre[x];            pushdown(pre[y]);            pushdown(y);            pushdown(x);            if (pre[pre[x]]==tgt)            {                rotate(x,ch[pre[x]][0]==x);            }            else            {                int kind=ch[pre[y]][0]==y;                if (ch[y][kind]==x)                {                    rotate(x,kind^1);                    rotate(x,kind);                }                else                {                    rotate(y,kind);                    rotate(x,kind);                }            }        }        pushup(x);        if (tgt==0) root=x;    }    void select(int k,int tgt)    {        int rt=root;        pushdown(rt);        while(true)        {            if (k<=size[ch[rt][0]]) rt=ch[rt][0];            else if (k==size[ch[rt][0]]+1) break;            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];            pushdown(rt);        }        splay(rt,tgt);    }    void newnode(int &r,int father,ll k)    {        r=++tot;        pre[r]=father;        size[r]=1;        flip[r]=setn[r]=0;        key[r]=k;        sum[r]=suff[r]=pref[r]=sub[r]=k;        ch[r][0]=ch[r][1]=0;    }    void build(int l,int r,int &x,int rt)    {        if (l>r) return;        int m=(l+r)>>1;        newnode(x,rt,a[m]);        build(l,m-1,ch[x][0],x);        build(m+1,r,ch[x][1],x);        pushup(x);    }    void init()    {        tot=root=0;        newnode(root,0,-(1<<29));        newnode(ch[root][1],root,-(1<<29));        suff[0]=pref[0]=sub[0]=-(1<<29);        suff[1]=pref[1]=sub[1]=-(1<<29);        suff[2]=pref[2]=sub[2]=-(1<<29);        build(1,n,ch[ch[root][1]][0],ch[root][1]);        pushup(ch[root][1]);        pushup(root);    }    void go_f(int r)    {        if(!r) return;        flip[r]^=1;        swap(ch[r][0],ch[r][1]);        swap(suff[r],pref[r]);    }    void go_s(int r,ll c)    {        if (!r) return ;        same[r]=true;        key[r]=c;        setn[r]=c;        sum[r]=(ll)(size[r]*c);        suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c);    }    void pushdownset(int r)    {        if (same[r])        {            go_s(ch[r][0],setn[r]);            go_s(ch[r][1],setn[r]);            same[r]=false;//            flip[r]=0;        }    }    void pushdownflip(int r)    {        if (flip[r])        {            go_f(ch[r][0]);            go_f(ch[r][1]);            flip[r]=0;        }    }    void pushdown(int r)    {        pushdownset(r);        pushdownflip(r);    }    void insert(int posi,int num)    {        ll c;        select(posi+1,0);        select(posi+2,root);        scanf("%I64d",&c);        newnode(ch[ch[root][1]][0],ch[root][1],c);        int rt=ch[ch[root][1]][0];        for(int i=2; i<=num; i++)        {            scanf("%I64d",&c);            newnode(ch[rt][1],rt,c);            rt=ch[rt][1];        }        while(pre[rt])        {            rt=pre[rt];            pushup(rt);        }        pushup(root);    }    void del(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        int k=ch[ch[root][1]][0];        pre[k]=0;        ch[ch[root][1]][0]=0;        pushup(ch[root][1]);        pushup(root);    }    void set_num(int posi,int num,ll c)    {        select(posi,0);        select(posi+num+1,root);        go_s(ch[ch[root][1]][0],c);        pushup(ch[root][1]);        pushup(root);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    void reverse(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        go_f(ch[ch[root][1]][0]);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    ll Sum(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        return sum[ch[ch[root][1]][0]];    }    ll Max_sum()    {        splay(1,0);        splay(2,root);        return sub[ch[ch[root][1]][0]];    }}spt;char cmd[30];int x,y,z;ll c;int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1; i<=n; i++)    scanf("%I64d",&a[i]);    spt.init();    getchar();    for (int i=1; i<=m; i++)    {//        cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n";        scanf("%s",cmd);        if (cmd[0]=='G')        {            scanf("%d%d",&x,&y);            printf("%I64d\n",spt.Sum(x,y));        }        else        if (cmd[0]=='I')        {            scanf("%d%d",&x,&y);            spt.insert(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='K')        {            scanf("%d%d%I64d",&x,&y,&c);            spt.set_num(x,y,c);        }        else        if (cmd[0]=='R')        {            scanf("%d%d",&x,&y);            spt.reverse(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='X')        {            printf("%I64d\n",spt.Max_sum());        }        else        if (cmd[0]=='D')        {            scanf("%d%d",&x,&y);            spt.del(x,y);        }    }    return 0;}


 

        可以发现..时间跟内存的消耗都是惊人的...因为我直接开了400W的数组....而且insert操作的时候我是直接用while循环,插成了一条链,这样在以后旋转的时候,时间消耗会很大。题目里保证了数列里最大只有50W个数,也就是说,根本没必要开400W的数组,delete的时候,把空间回收再利用的话,50W的数组就够用了。参考了一下各路大神的代码,加上了内存回收,并且在insert的时候,直接插成一颗平衡树,时间和空间都会大大缩小。

 

#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=500000+5000;int pre[maxn],ch[maxn][2];int stk[maxn];int top;int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{    void pushup(int r)    {        if (r==0) return;        size[r]=size[ch[r][0]]+1+size[ch[r][1]];        sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]];        pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]]));        suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]]));        sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]);        sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]]));    }    void rotate(int x,int kind)    {        int y=pre[x];        pushdown(y);        pushdown(x);        ch[y][!kind]=ch[x][kind];        pre[ch[x][kind]]=y;        if (pre[y])        {            ch[pre[y]][ch[pre[y]][1]==y]=x;        }        pre[x]=pre[y];        ch[x][kind]=y;        pre[y]=x;        pushup(y);        pushup(x);    }    void splay(int x,int tgt)    {        pushdown(x);        while(pre[x]!=tgt)        {            int y=pre[x];            pushdown(pre[y]);            pushdown(y);            pushdown(x);            if (pre[pre[x]]==tgt)            {                rotate(x,ch[pre[x]][0]==x);            }            else            {                int kind=ch[pre[y]][0]==y;                if (ch[y][kind]==x)                {                    rotate(x,kind^1);                    rotate(x,kind);                }                else                {                    rotate(y,kind);                    rotate(x,kind);                }            }        }        pushup(x);        if (tgt==0) root=x;    }    void select(int k,int tgt)    {        int rt=root;        pushdown(rt);        while(true)        {            if (k<=size[ch[rt][0]]) rt=ch[rt][0];            else if (k==size[ch[rt][0]]+1) break;            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];            pushdown(rt);        }        splay(rt,tgt);    }    void newnode(int &r,int father,ll k)    {        if (top)        {            r=stk[top--];        }        else r=++tot;        pre[r]=father;        size[r]=1;        flip[r]=setn[r]=0;        same[r]=0;        key[r]=k;        sum[r]=suff[r]=pref[r]=sub[r]=k;        ch[r][0]=ch[r][1]=0;    }    void build(int l,int r,int &x,int rt)    {        if (l>r) return;        int m=(l+r)>>1;        newnode(x,rt,a[m]);        build(l,m-1,ch[x][0],x);        build(m+1,r,ch[x][1],x);        pushup(x);    }    void init()    {        tot=root=0;        top=0;        newnode(root,0,-(1<<29));        newnode(ch[root][1],root,-(1<<29));        suff[0]=pref[0]=sub[0]=-(1<<29);        suff[1]=pref[1]=sub[1]=-(1<<29);        suff[2]=pref[2]=sub[2]=-(1<<29);        build(1,n,ch[ch[root][1]][0],ch[root][1]);        pushup(ch[root][1]);        pushup(root);    }    void go_f(int r)    {        if(!r) return;        flip[r]^=1;        swap(ch[r][0],ch[r][1]);        swap(suff[r],pref[r]);    }    void go_s(int r,ll c)    {        if (!r) return ;        same[r]=true;        key[r]=c;        setn[r]=c;        sum[r]=(ll)(size[r]*c);        suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c);    }    void pushdownset(int r)    {        if (same[r])        {            go_s(ch[r][0],setn[r]);            go_s(ch[r][1],setn[r]);            same[r]=false;//            flip[r]=0;        }    }    void pushdownflip(int r)    {        if (flip[r])        {            go_f(ch[r][0]);            go_f(ch[r][1]);            flip[r]=0;        }    }    void pushdown(int r)    {        pushdownset(r);        pushdownflip(r);    }    void insert(int posi,int num)    {        ll c;        select(posi+1,0);        select(posi+2,root);        for (int i=1; i<=num; i++)        scanf("%I64d",&a[i]);        build(1,num,ch[ch[root][1]][0],ch[root][1]);    }    void del(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        int k=ch[ch[root][1]][0];        recover(k);        pre[k]=0;        ch[ch[root][1]][0]=0;        pushup(ch[root][1]);        pushup(root);    }    void set_num(int posi,int num,ll c)    {        select(posi,0);        select(posi+num+1,root);        go_s(ch[ch[root][1]][0],c);        pushup(ch[root][1]);        pushup(root);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    void reverse(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        go_f(ch[ch[root][1]][0]);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    ll Sum(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        return sum[ch[ch[root][1]][0]];    }    ll Max_sum()    {        splay(1,0);        splay(2,root);        return sub[ch[ch[root][1]][0]];    }    void recover(int r)    {        if (!r) return;        stk[++top]=r;        recover(ch[r][0]);        recover(ch[r][1]);    }}spt;char cmd[30];int x,y,z;ll c;int main(){    freopen("in.txt","r",stdin);    freopen("out.txt","w",stdout);    scanf("%d%d",&n,&m);    for (int i=1; i<=n; i++)    scanf("%I64d",&a[i]);    spt.init();    getchar();    for (int i=1; i<=m; i++)    {//        cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n";        scanf("%s",cmd);        if (cmd[0]=='G')        {            scanf("%d%d",&x,&y);            printf("%I64d\n",spt.Sum(x,y));        }        else        if (cmd[0]=='I')        {            scanf("%d%d",&x,&y);            spt.insert(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='K')        {            scanf("%d%d%I64d",&x,&y,&c);            spt.set_num(x,y,c);        }        else        if (cmd[0]=='R')        {            scanf("%d%d",&x,&y);            spt.reverse(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='X')        {            printf("%I64d\n",spt.Max_sum());        }        else        if (cmd[0]=='D')        {            scanf("%d%d",&x,&y);            spt.del(x,y);        }    }    return 0;}


BZOJ上交的代码:

#include <iostream>#include <cstdio>#include <algorithm>#include <string>#include <cstring>using namespace std;typedef long long ll;const int maxn=500000+5000;int pre[maxn],ch[maxn][2];int stk[maxn];int top;int flip[maxn];ll setn[maxn];int size[maxn];ll key[maxn],sub[maxn],suff[maxn],pref[maxn],sum[maxn],a[maxn];bool same[maxn];int root,tot,n,m;int p,q,tt,t,k,r;struct splaytree{    void pushup(int r)    {        if (r==0) return;        size[r]=size[ch[r][0]]+1+size[ch[r][1]];        sum[r]=sum[ch[r][0]]+key[r]+sum[ch[r][1]];        pref[r]=max(pref[ch[r][0]],sum[ch[r][0]]+key[r]+max(0LL,pref[ch[r][1]]));        suff[r]=max(suff[ch[r][1]],sum[ch[r][1]]+key[r]+max(0LL,suff[ch[r][0]]));        sub[r]=max(0LL,suff[ch[r][0]])+key[r]+max(0LL,pref[ch[r][1]]);        sub[r]=max(sub[r],max(sub[ch[r][0]],sub[ch[r][1]]));    }    void rotate(int x,int kind)    {        int y=pre[x];        pushdown(y);        pushdown(x);        ch[y][!kind]=ch[x][kind];        pre[ch[x][kind]]=y;        if (pre[y])        {            ch[pre[y]][ch[pre[y]][1]==y]=x;        }        pre[x]=pre[y];        ch[x][kind]=y;        pre[y]=x;        pushup(y);        pushup(x);    }    void splay(int x,int tgt)    {        pushdown(x);        while(pre[x]!=tgt)        {            int y=pre[x];            pushdown(pre[y]);            pushdown(y);            pushdown(x);            if (pre[pre[x]]==tgt)            {                rotate(x,ch[pre[x]][0]==x);            }            else            {                int kind=ch[pre[y]][0]==y;                if (ch[y][kind]==x)                {                    rotate(x,kind^1);                    rotate(x,kind);                }                else                {                    rotate(y,kind);                    rotate(x,kind);                }            }        }        pushup(x);        if (tgt==0) root=x;    }    void select(int k,int tgt)    {        int rt=root;        pushdown(rt);        while(true)        {            if (k<=size[ch[rt][0]]) rt=ch[rt][0];            else if (k==size[ch[rt][0]]+1) break;            else k-=(size[ch[rt][0]]+1),rt=ch[rt][1];            pushdown(rt);        }        splay(rt,tgt);    }    void newnode(int &r,int father,ll k)    {        if (top)        {            r=stk[top--];        }        else r=++tot;        pre[r]=father;        size[r]=1;        flip[r]=setn[r]=0;        same[r]=0;        key[r]=k;        sum[r]=suff[r]=pref[r]=sub[r]=k;        ch[r][0]=ch[r][1]=0;    }    void build(int l,int r,int &x,int rt)    {        if (l>r) return;        int m=(l+r)>>1;        newnode(x,rt,a[m]);        build(l,m-1,ch[x][0],x);        build(m+1,r,ch[x][1],x);        pushup(x);    }    void init()    {        tot=root=0;        top=0;        newnode(root,0,-(1<<29));        newnode(ch[root][1],root,-(1<<29));        suff[0]=pref[0]=sub[0]=-(1<<29);        suff[1]=pref[1]=sub[1]=-(1<<29);        suff[2]=pref[2]=sub[2]=-(1<<29);        build(1,n,ch[ch[root][1]][0],ch[root][1]);        pushup(ch[root][1]);        pushup(root);    }    void go_f(int r)    {        if(!r) return;        flip[r]^=1;        swap(ch[r][0],ch[r][1]);        swap(suff[r],pref[r]);    }    void go_s(int r,ll c)    {        if (!r) return ;        same[r]=true;        key[r]=c;        setn[r]=c;        sum[r]=(ll)(size[r]*c);        suff[r]=pref[r]=sub[r]=max(c,(ll)size[r]*c);    }    void pushdownset(int r)    {        if (same[r])        {            go_s(ch[r][0],setn[r]);            go_s(ch[r][1],setn[r]);            same[r]=false;//            flip[r]=0;        }    }    void pushdownflip(int r)    {        if (flip[r])        {            go_f(ch[r][0]);            go_f(ch[r][1]);            flip[r]=0;        }    }    void pushdown(int r)    {        pushdownset(r);        pushdownflip(r);    }    void insert(int posi,int num)    {        ll c;        select(posi+1,0);        select(posi+2,root);        for (int i=1; i<=num; i++)        scanf("%lld",&a[i]);        build(1,num,ch[ch[root][1]][0],ch[root][1]);    }    void del(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        int k=ch[ch[root][1]][0];        recover(k);        pre[k]=0;        ch[ch[root][1]][0]=0;        pushup(ch[root][1]);        pushup(root);    }    void set_num(int posi,int num,ll c)    {        select(posi,0);        select(posi+num+1,root);        go_s(ch[ch[root][1]][0],c);        pushup(ch[root][1]);        pushup(root);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    void reverse(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        go_f(ch[ch[root][1]][0]);        int k=ch[ch[root][1]][0];//        splay(k,0);    }    ll Sum(int posi,int num)    {        select(posi,0);        select(posi+num+1,root);        return sum[ch[ch[root][1]][0]];    }    ll Max_sum()    {        splay(1,0);        splay(2,root);        return sub[ch[ch[root][1]][0]];    }    void recover(int r)    {        if (!r) return;        stk[++top]=r;        recover(ch[r][0]);        recover(ch[r][1]);    }}spt;char cmd[30];int x,y,z;ll c;int main(){    scanf("%d%d",&n,&m);    for (int i=1; i<=n; i++)    scanf("%lld",&a[i]);    spt.init();    getchar();    for (int i=1; i<=m; i++)    {//        cout<<ch[0][0]<<"---"<<ch[0][1]<<"--"<<pre[0]<<"hit----\n";        scanf("%s",cmd);        if (cmd[0]=='G')        {            scanf("%d%d",&x,&y);            printf("%lld\n",spt.Sum(x,y));        }        else        if (cmd[0]=='I')        {            scanf("%d%d",&x,&y);            spt.insert(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='K')        {            scanf("%d%d%lld",&x,&y,&c);            spt.set_num(x,y,c);        }        else        if (cmd[0]=='R')        {            scanf("%d%d",&x,&y);            spt.reverse(x,y);        }        else        if (cmd[0]=='M' && cmd[2]=='X')        {            printf("%lld\n",spt.Max_sum());        }        else        if (cmd[0]=='D')        {            scanf("%d%d",&x,&y);            spt.del(x,y);        }    }    return 0;}