bzoj 1500: [NOI2005]维修数列 splay

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 6556  Solved: 1963
[Submit][Status]

Description

Input

输入文件的第1行包含两个数N和M,N表示初始时数列中数的个数,M表示要进行的操作数目。第2行包含N个数字,描述初始时的数列。以下M行,每行一条命令,格式参见问题描述中的表格。

Output

对于输入数据中的GET-SUM和MAX-SUM操作,向输出文件依次打印结果,每个答案(数字)占一行。

Sample Input

9 8
2 -6 3 5 1 -5 -3 6 3
GET-SUM 5 4
MAX-SUM
INSERT 8 3 -5 7 2
DELETE 12 1
MAKE-SAME 3 3 2
REVERSE 3 6
GET-SUM 5 4
MAX-SUM

Sample Output

-1
10
1
10

HINT

 splay的難點就在於信息的同步與下放。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<queue>
using namespace std;
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#define MAXN 1100000
#define MAXV MAXN*2
#define MAXE MAXV*2
#define MAXT MAXN
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
typedef long long qword;
inline int nextInt()
{
        char ch;
        int x=0;
        bool flag=false;
        do
                ch=(char)getchar(),flag=(ch=='-')?true:flag;
        while(ch<'0'||ch>'9');
        do x=x*10+ch-'0';
        while (ch=(char)getchar(),ch<='9' && ch>='0');
        return x*(flag?-1:1);
}

int n,m;
struct Splay_tree
{
        int ch[MAXT][2];
        int pnt[MAXT];
        int val[MAXT];
        int siz[MAXT];
        int sum[MAXT];
        int lx[MAXT],rx[MAXT],mx[MAXT];
        int chgf[MAXT],rev[MAXT];
        int stack[MAXT],tops;
        int root;
        queue<int> Q;
        Splay_tree()
        {
                root=0;
                for (int i=1;i<=1000000;i++)
                        Q.push(i);
        }
        int nextNode()//支持垃圾回收機制
        {
                int now=Q.front();
                Q.pop();
                if (ch[now][0])
                        Q.push(ch[now][0]);
                if (ch[now][1])
                        Q.push(ch[now][1]);
                ch[now][0]=ch[now][1]=0;
                return now;
        }
        void Rotate(int now)
        {
                int p=pnt[now],anc=pnt[p];
                int dir=(ch[p][0]==now);
                if (anc)
                {
                        ch[anc][ch[anc][1]==p]=now;
                }
                pnt[now]=anc;
                ch[p][1-dir]=ch[now][dir];
                pnt[ch[now][dir]]=p;
                pnt[p]=now;
                ch[now][dir]=p;
                up(p);
                up(now);
        }
        void Reverse(int now)
        {
                rev[ch[now][0]]^=1;
                rev[ch[now][1]]^=1;
                swap(ch[now][0],ch[now][1]);
                swap(lx[ch[now][0]],rx[ch[now][0]]);
                swap(lx[ch[now][1]],rx[ch[now][1]]);
                up(now);//容易忽略,由於改變了子節點的lx,rx值,需要更新
        }
        void Reset(int now,int v)//注意
        {
                lx[now]=rx[now]=v*siz[now];
                mx[now]=sum[now]=siz[now]*v;
                val[now]=v;
                chgf[now]=v;
        }
        void down(int now)
        {
                if (rev[now])
                {
                        Reverse(now);//
                        rev[now]=0;
                }
                if (chgf[now]!=INF)
                {
                        Reset(ch[now][0],chgf[now]);
                        Reset(ch[now][1],chgf[now]);
                        chgf[now]=INF;
                }
        }
        void up(int now)
        {
                if (!now)
                {
                        //cout<<"Update error"<<endl;;
                        throw "Update 0";
                }
                sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+val[now];
                siz[now]=siz[ch[now][0]]+siz[ch[now][1]]+1;
                lx[now]=sum[ch[now][0]]+val[now]+lx[ch[now][1]];
                lx[now]=max(lx[now],sum[ch[now][0]]+val[now]);
                if (ch[now][0])lx[now]=max(lx[now],lx[ch[now][0]]);

                rx[now]=sum[ch[now][1]]+val[now]+rx[ch[now][0]];
                rx[now]=max(rx[now],sum[ch[now][1]]+val[now]);
                if (ch[now][1])rx[now]=max(rx[now],rx[ch[now][1]]);


                mx[now]=max(max(val[now]+rx[ch[now][0]],val[now]+lx[ch[now][1]])
                                ,max(val[now],val[now]+rx[ch[now][0]]+lx[ch[now][1]]));
                if (ch[now][0])mx[now]=max(mx[now],mx[ch[now][0]]);
                if (ch[now][1])mx[now]=max(mx[now],mx[ch[now][1]]);
        }
        int Splay(int now,int tp=0)
        {
                int x=now;
                tops=-1;
                if (now==tp)return now;
                while (x!=0)/**/
                {
                        stack[++tops]=x;
                        x=pnt[x];
                }
                while (tops>=0)
                        down(stack[tops--]);
                while (pnt[now]!=tp)/**/
                {
                        int p=pnt[now],anc=pnt[p];
                        if (anc==tp)/**/
                        {
                                Rotate(now);
                        }else
                        {
                                if ((ch[anc][0]==p) == (ch[p][1]==now))
                                {
                                        Rotate(p);
                                        Rotate(now);
                                }else
                                {
                                        Rotate(now);
                                        Rotate(now);
                                }
                        }
                }
                if (!tp)root=now;
                return now;
        }
        int Get_kth(int now,int rk)
        {
                down(now);//這裏要先下放標記
                if (rk==siz[ch[now][0]]+1)
                {
                        return now;
                }
                if (siz[ch[now][0]]<rk)
                        return Get_kth(ch[now][1],rk-1-siz[ch[now][0]]);
                else
                        return Get_kth(ch[now][0],rk);
        }
        void Insert(int pos,int v)
        {
                int now;
                now=nextNode();
                val[now]=v;
                chgf[now]=INF;
                rev[now]=0;
                mx[now]=sum[now]=v;
                lx[now]=rx[now]=v;//mx 易忽略
                if (!pos)
                {
                        Splay(Get_kth(root,1));
                        pnt[root]=now;
                        ch[now][1]=root;
                        root=now;//衝定義根節點
                        up(now);
                        return ;
                }else
                {
                        Splay(Get_kth(root,pos));
                        pnt[root]=now;
                        pnt[ch[root][1]]=now;
                        ch[now][0]=root;
                        ch[now][1]=ch[root][1];
                        ch[root][1]=0;
                        if (root)up(root);
                        root=now;
                        up(now);
                }
        }
        void Insert(int pos,int *arr,int n)//區間加數
        {
                int now=0,kroot;
                Build_tree(arr,now,0,n-1);
                //Scan(now);
                if (!root)
                {
                        root=now;
                        return ;
                }
                if (!pos)
                {
                        Splay(Get_kth(root,1));
                        pnt[now]=root;
                        ch[root][0]=now;
                        up(root);
                }else if (pos==siz[root])
                {
                        Splay(Get_kth(root,siz[root]));
                        pnt[now]=root;
                        ch[root][1]=now;
                        up(root);
                }else
                {
                        Splay(Get_kth(root,pos));
                        Splay(Get_kth(root,pos+1),root);
                        ch[ch[root][1]][0]=now;
                        pnt[now]=ch[root][1];
                        up(ch[root][1]);
                        up(root);
                }
        }
        void Delete(int l,int r)
        {
                if (l==1 && r==siz[root])
                {
                        Q.push(root);
                        root=0;
                }else if (l==1)
                {
                        Splay(Get_kth(root,r+1));
                        Q.push(ch[root][0]);
                        ch[root][0]=0;
                        up(root);
                }else if (r==siz[root])
                {
                        Splay(Get_kth(root,l-1));
                        Q.push(ch[root][1]);
                        ch[root][1]=0;
                        up(root);
                }else
                {
                        Splay(Get_kth(root,l-1));
                        Splay(Get_kth(root,r+1),root);
                        Q.push(ch[ch[root][1]][0]);
                        ch[ch[root][1]][0]=0;
                        up(ch[root][1]);
                        up(root);
                }
        }
        void Scan(int now)
        {
                if (!now)return ;
                down(now);
                if (sum[now]!=sum[ch[now][0]]+sum[ch[now][1]]+val[now])throw "Scan_up";
                if (ch[now][0] && pnt[ch[now][0]]!=now)throw "Scan";
                Scan(ch[now][0]);
                printf("%d ",val[now]);
                if (ch[now][1] && pnt[ch[now][1]]!=now)throw "Scan";
                Scan(ch[now][1]);
        }
        qword Get_sum(int l,int r)
        {
                if (l==1 && r==siz[root])
                {
                        return sum[root];
                }else if (l==1)
                {
                        Splay(Get_kth(root,r+1));
                        return sum[ch[root][0]];
                }else if (r==siz[root])
                {
                        Splay(Get_kth(root,l-1));
                        return sum[ch[root][1]];
                }else
                {
                        Splay(Get_kth(root,l-1));
                        Splay(Get_kth(root,r+1),root);
                        return sum[ch[ch[root][1]][0]];
                }
        }
        qword Max_sum(int l,int r)
        {
                if (l==1 && r==siz[root])
                {
                        return mx[root];
                }else if (l==1)
                {
                        Splay(Get_kth(root,r+1));
                        return mx[ch[root][0]];
                }else if (r==siz[root])
                {
                        Splay(Get_kth(root,l-1));
                        return mx[ch[root][1]];
                }else
                {
                        Splay(Get_kth(root,l-1));
                        Splay(Get_kth(root,r+1),root);
                        return mx[ch[ch[root][1]][0]];
                }
        }
        void Build_tree(int *arr,int &now,int l,int r)
        {
                if (r<l)return ;
                int mid=(l+r)>>1;
                now=nextNode();
                val[now]=arr[mid];
                chgf[now]=INF;
                rev[now]=0;
                mx[now]=sum[now]=arr[mid];
                lx[now]=rx[now]=arr[mid];
                if (l<=mid-1)
                        Build_tree(arr,ch[now][0],l,mid-1);
                if (mid+1<=r)
                        Build_tree(arr,ch[now][1],mid+1,r);
                pnt[ch[now][0]]=now;
                pnt[ch[now][1]]=now;
                up(now);
        }
        void Make_Reverse(int l,int r)
        {
                if (l==1 && r==siz[root])
                {
                        Reverse(root);
                        up(root);
                }else if (l==1)
                {
                        Splay(Get_kth(root,r+1));
                        Reverse(ch[root][0]);
                        up(root);
                }else if (r==siz[root])
                {
                        Splay(Get_kth(root,l-1));
                        Reverse(ch[root][1]);
                        up(root);
                }else
                {
                        Splay(Get_kth(root,l-1));
                        Splay(Get_kth(root,r+1),root);
                        Reverse(ch[ch[root][1]][0]);
                        up(ch[root][1]);
                        up(root);//對子樹的處理都要更新至根節點
                }
        }
        void Make_same(int l,int r,int v)
        {
                if (l==1 && r==siz[root])
                {
                        Reset(root,v);
                        up(root);
                }else if (l==1)
                {
                        Splay(Get_kth(root,r+1));
                        Reset(ch[root][0],v);
                        up(root);
                }else if (r==siz[root])
                {
                        Splay(Get_kth(root,l-1));
                        Reset(ch[root][1],v);
                        up(root);
                }else
                {
                        Splay(Get_kth(root,l-1));
                        Splay(Get_kth(root,r+1),root);
                        Reset(ch[ch[root][1]][0],v);
                        up(ch[root][1]);
                        up(root);
                }
        }
}splay;
int num[MAXN];
int main()
{
        //freopen("input.txt","r",stdin);
        //freopen("output.txt","w",stdout);
        //freopen("sequence7.in","r",stdin);
        int i,j,k;
        int x,y,z;
        char opt[MAXN];
        try
        {
                scanf("%d%d",&n,&m);
                for (i=0;i<n;i++)
                        scanf("%d",num+i);
                scanf("
");
                splay.Build_tree(num,splay.root,0,n-1);
                for (i=0;i<m;i++)
                {
                        scanf("%s",opt);
                //        cout<<opt<<endl;
                        if (opt[2]=='T')//GET_SUM
                        {
                                scanf("%d%d",&x,&y);
                                printf(LL "
",splay.Get_sum(x,x+y-1));
                        }else if (opt[2]=='X')//MAX_SUM
                        {
                                printf(LL"
",splay.Max_sum(1,splay.siz[splay.root]));
                        }else if (opt[2]=='S')//INSERT
                        {
                                scanf("%d%d",&x,&y);
                                for (j=0;j<y;j++)
                                {
                                        scanf("%d",&num[j]);
                                }
                                splay.Insert(x,num,y);
                        }else if (opt[2]=='L')//DELETE
                        {
                                scanf("%d%d",&x,&y);
                                splay.Delete(x,x+y-1);
                        }else if (opt[2]=='K')//MAKE_SAME
                        {
                                scanf("%d%d%d",&x,&y,&z);
                                splay.Make_same(x,x+y-1,z);
                        }else if (opt[2]=='V')//REVERSE
                        {
                                scanf("%d%d",&x,&y);
                                splay.Make_Reverse(x,x+y-1);
                        }
                        //splay.Scan(splay.root);
                        //cout<<endl;
                        scanf("
");
                }
        }
        catch (const char * err)
        {
                cerr<<err<<endl;
                return 0;
        }
        return 0;
}
by mhy12345(http://www.cnblogs.com/mhy12345/) 未经允许请勿转载

本博客已停用,新博客地址:http://mhy12345.xyz

原文地址:https://www.cnblogs.com/mhy12345/p/4022424.html