NOI2005维护数列 伸展树splay

        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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值