码迷,mamicode.com
首页 > 其他好文 > 详细

Splay必做题 [NOI2005]维修数列

时间:2014-10-21 10:00:37      阅读:337      评论:0      收藏:0      [点我收藏+]

标签:des   style   blog   http   color   io   os   ar   for   

1500: [NOI2005]维修数列

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 6577  Solved: 1978
[Submit][Status]

Description

bubuko.com,布布扣

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

 

bubuko.com,布布扣

/**************************************************************
    Problem: 1500
    User: 452181625
    Language: C++
    Result: Accepted
    Time:7376 ms
    Memory:25708 kb
****************************************************************/

//参考网址:http://blog.163.com/chensmiles/blog/static/1214639912010111151243144
 
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define N 500010
 
int n,m,num[N];
struct SplayTree
{
    int sz[N],ch[N][2],pre[N],que[N],sta[N];
    int top1,top2,root;
 
    int sum[N],maxm[N],maxl[N],maxr[N],val[N];
    bool ro[N],same[N];
 
    inline void SameNode(int x,int c)  //将以x为根的子树全部修改为c
    {
        if(x==0) return;
        val[x]=c;
        sum[x]=sz[x]*val[x];
        maxm[x]=maxl[x]=maxr[x]=max(sum[x],val[x]);
        same[x]=1; //延迟标记
    }
 
    inline void ReverseNode(int x) //将以x为根节点的子树翻转
    {
        if(x==0) return;
        ch[x][0]^=ch[x][1]^=ch[x][0]^=ch[x][1];
        maxl[x]^=maxr[x]^=maxl[x]^= maxr[x];
        ro[x]^=1; //延迟标记
    }
 
    inline void PushDown(int x)
    {
        if(x==0) return;
        if(ro[x])
        {
            ReverseNode(ch[x][0]);
            ReverseNode(ch[x][1]);
            ro[x]^=1;
        }
        if(same[x])
        {
            SameNode(ch[x][0],val[x]);
            SameNode(ch[x][1],val[x]);
            same[x]=0;
        }
    }
 
    inline void PushUp(int x)
    {
        if(x==0) return;
        sz[x]=1+sz[ch[x][0]]+sz[ch[x][1]];
        sum[x]=val[x]+sum[ch[x][0]]+sum[ch[x][1]];
        maxl[x]=max(maxl[ch[x][0]],sum[ch[x][0]]+val[x]+max(0,maxl[ch[x][1]]));
        maxr[x]=max(maxr[ch[x][1]],sum[ch[x][1]]+val[x]+max(0,maxr[ch[x][0]]));
        maxm[x]=max(max(maxl[ch[x][1]],0)+val[x]+max(maxr[ch[x][0]],0),max(maxm[ch[x][0]],maxm[ch[x][1]]));
    }
 
    inline void Rotate(int x,int c) 
    {
        int y=pre[x];
        PushDown(y);
        PushDown(x);
        ch[y][!c]=ch[x][c];
        if(ch[x][c]) pre[ch[x][c]]=y;
        pre[x]=pre[y];
        if(pre[y]) ch[pre[y]][ch[pre[y]][1]==y]=x;
        ch[x][c]=y;
        pre[y]=x;
        PushUp(y);
        if(y==root) root=x;
    }
 
    inline void Splay(int x,int f) //把x节点转到f节点的下面
    { 
        PushDown(x);
        while(pre[x]!=f) 
        {
            PushDown(pre[pre[x]]); 
            PushDown(pre[x]);
            PushDown(x);
            if(pre[pre[x]]==f) Rotate(x,ch[pre[x]][0]==x); //单旋转
            else
            {
                int y=pre[x],z=pre[y];
                int c=(ch[z][0]==y);
                if(ch[y][c]==x) Rotate(x,!c),Rotate(x,c); //之字型旋转
                else Rotate(y,c),Rotate(x,c); //一字型旋转
            }
        }
        PushUp(x);
        if(f==0) root=x;
    }
 
    inline void SplayKth(int k,int f) //将第k个元素转到f节点的下面
    { 
        int x=root;
        k+=1;
        while(1)
        {
            PushDown(x);
            if(k==sz[ch[x][0]]+1) break;
            else if(k<=sz[ch[x][0]]) x=ch[x][0];
            else k-=sz[ch[x][0]]+1,x=ch[x][1];
        }
        Splay(x,f);
    }
 
    inline void Erase(int x) //删除以x节点为祖先的子树,回收内存
    { 
        int head=1,rear=1;
        que[head]=x;
        while(head<=rear)
        {
            sta[++top2]=que[head];
            if(ch[que[head]][0]) que[++rear]=ch[que[head]][0];
            if(ch[que[head]][1]) que[++rear]=ch[que[head]][1];
            head++;
        }
    }
 
    void debug()
    {
        cout<<"root = "<<root<<endl;
        traval(root);
    }
 
    void traval(int x) 
    {
        if (x)
        {
            traval(ch[x][0]);
            cout <<x<<" size: "<<sz[x]<<" left: "<<ch[x][0]<<" right: "<<ch[x][1]<<" pre: "<<pre[x]<<" val: "<<val[x]<<" sum: "<<sum[x]<<endl;
            traval(ch[x][1]);
        }
    }
 
    inline void NewNode(int &x,int c)
    {
        if(top2) x=sta[top2--];
        else x=++top1;
        ch[x][0]=ch[x][1]=pre[x]=0;
        sz[x]=1;
        ro[x]=same[x]=0;
        val[x]=sum[x]=maxm[x]=maxl[x]=maxr[x]=c;
    }
 
    inline void Build(int &x,int l,int r,int f) 
    {
        if(l>r) return;
        int m=(l+r)>>1;
        NewNode(x,num[m]);
        Build(ch[x][0],l,m-1,x);
        Build(ch[x][1],m+1,r,x);
        pre[x]=f;
        PushUp(x);
    }
 
    inline void Init(int n) 
    {
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        ro[0]=same[0]=0;
        maxr[0]=maxl[0]=maxm[0]=-1001;
        sum[0]=0;
        root=top1=top2=0;
        for(int i=1;i<=n;i++) scanf("%d",&num[i]);
        Build(root,0,n+1,0);
    }
 
    void GetSum()
    {
        int a,b;
        scanf("%d%d",&a,&b);
        SplayKth(a-1,0);
        SplayKth(a+b,root);
        printf("%d\n", sum[ch[ch[root][1]][0]]);
    }
 
    void MaxSum()
    {
        SplayKth(0, 0);
        SplayKth(sz[root]-1,root);
        printf("%d\n",maxm[ch[ch[root][1]][0]]);
    }
 
    void Insert() //插入区间、原理:将树旋转、第pos个数旋转到根、第pos+1个数到根的右孩子、然后再根的右孩子的左孩子处建树、因此结果是插入的数在第pos到pos+1之间、达到要求
    {
        int pos,tot;
        scanf("%d%d",&pos,&tot);
        for(int i=1;i<=tot;i++) scanf("%d", &num[i]);
        SplayKth(pos,0);
        SplayKth(pos+1,root);
        Build(ch[ch[root][1]][0],1,tot,ch[root][1]);
        PushUp(ch[root][1]);
        PushUp(root);
    }
 
    void Delete() //删除区间、原理:将树旋转、第pos-1个数旋转到根、第pos+tot个数到根的右孩子、然后删除根的右孩子的左孩子即可
    {
        int pos,tot;
        scanf("%d%d",&pos,&tot);
        SplayKth(pos-1,0);
        SplayKth(pos+tot,root);
        Erase(ch[ch[root][1]][0]);
        ch[ch[root][1]][0]=0;
        PushUp(ch[root][1]);
        PushUp(root);
    }
 
    void MakeSame()  //统一修改、原理:第pos-1个数旋转到根、第pos+tot个数到根的右孩子、然后将根的右孩子的左子树全部修改为c即可
    {
        int pos,tot,c;
        scanf("%d%d%d",&pos,&tot,&c);
        SplayKth(pos-1,0);
        SplayKth(pos+tot,root);
        SameNode(ch[ch[root][1]][0],c);
    }

 
    void Reverse()  //区间翻转、原理:第pos-1个数旋转到根、第pos+tot个数到根的右孩子、然后将根的右孩子的左子树翻转即可
    {
        int pos,tot;
        scanf("%d%d",&pos,&tot);
        SplayKth(pos-1,0);
        SplayKth(pos+tot,root);
        ReverseNode(ch[ch[root][1]][0]);
    }
}t;
 
int main()
{
    char op[20];
    scanf("%d%d",&n,&m);
    t.Init(n);
    while(m--)
    {
        scanf("%s",&op);
        if(op[0]==G) t.GetSum();
        else if(op[0]==M && op[2]==X) t.MaxSum();
        else if(op[0]==I) t.Insert();
        else if(op[0]==D) t.Delete();
        else if(op[0]==M && op[2]==K) t.MakeSame();
        else if(op[0]==R) t.Reverse();
    }
    return 0;
}

 

Splay必做题 [NOI2005]维修数列

标签:des   style   blog   http   color   io   os   ar   for   

原文地址:http://www.cnblogs.com/hate13/p/4039442.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!