【splay】BZOJ 1500: [NOI2005]维修数列

BZOJ 1500 维修数列


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

N,M<=100000


Solution

一道日狗的题目。。
听说一小时之内A了这题才算掌握了splay?
机房的同学们都是一个晚上就A了
我这个大蒟蒻用了一天。。
最后还是某和我一起苦逼改题的同学的提醒我才A的。。

  • insert
    和普通的insert没什么区别吧..
    有两种添加方法:1.一条链添加下去,2.利用build函数(2方法好一些然而博主蒟蒻打的第一种)
    记得要update!

  • delete
    普通的delete..删除方法就是把L-1旋到根,R+1旋到根的右节点,然后把右节点的左子树删除即可
    记得要update!

  • make_same
    打tag
    这里有个很重要的细节,不要把tag作为值下传.
    tag要作为一个标记表示修改过了而不是一个值,值由当前节点的v来下传!
    因为数据中有make_same 0的情况,如果使用tag存值的方法tag等于0时标记不会下传!
    改了一个下午没改出来..最后还是在同学的提醒下才弄出来的。。

  • rev操作
    和普通的rev一样,打标记下传.

  • get_sum
    这个应该也是很简单的,update即可。

  • max_num
    最难的一个操作
    对于一个区间的最大子区间,我们在两种中取max:
      1.左子树的最大区间/右子树的最大区间
      2.右子树从左端开始向右的最大区间+左子树从右端开始向左的最大区间
    而一段区间的两端开始的最大值(lx,rx)求法就是在以下两种中取max:
      1.假如求lx,则是当前区间左子树区间的lx,rx反之
      2.假如求lx,则是当前区间左子树区间的sum+右子树区间的lx,rx反之
    注意rev操作要把左右各子树的lx和rx交换

其他:数组空间不够,需要使用队列回收删除节点重新利用!

打完以后整个人都不好了..

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>

using namespace std;

#define maxn 500001

int root,size,que[maxn],head=1,tail=0,a[maxn+233],stack[maxn],top=0;

bool ok[maxn];

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

struct splay{
    int size,ch[2],v,fa,sum,lx,rx,mx;
    bool rev,tag;
}t[maxn],E;

char s[233];

void pushdown(int k)
{
    if(t[k].tag)
    {
        t[k].rev=0;
        if(t[k].ch[0])t[t[k].ch[0]].tag=t[k].tag,t[t[k].ch[0]].v=t[k].v,t[t[k].ch[0]].sum=t[k].v*t[t[k].ch[0]].size;
        if(t[k].ch[1])t[t[k].ch[1]].tag=t[k].tag,t[t[k].ch[1]].v=t[k].v,t[t[k].ch[1]].sum=t[k].v*t[t[k].ch[1]].size;
        if(t[k].v>=0)
        {
            if(t[k].ch[1])t[t[k].ch[1]].lx=t[t[k].ch[1]].rx=t[t[k].ch[1]].mx=t[t[k].ch[1]].sum;
            if(t[k].ch[0])t[t[k].ch[0]].lx=t[t[k].ch[0]].rx=t[t[k].ch[0]].mx=t[t[k].ch[0]].sum;
        }
        else 
        {
            if(t[k].ch[1])t[t[k].ch[1]].lx=t[t[k].ch[1]].rx=0,t[t[k].ch[1]].mx=t[k].v;
            if(t[k].ch[0])t[t[k].ch[0]].lx=t[t[k].ch[0]].rx=0,t[t[k].ch[0]].mx=t[k].v;
        }
        t[k].tag=0;
    }
    if(t[k].rev)
    {
        t[k].rev=0;
        t[t[k].ch[0]].rev^=1;
        t[t[k].ch[1]].rev^=1;
        swap(t[t[k].ch[0]].ch[0],t[t[k].ch[0]].ch[1]);
        swap(t[t[k].ch[1]].ch[0],t[t[k].ch[1]].ch[1]);
        swap(t[t[k].ch[1]].lx,t[t[k].ch[1]].rx);
        swap(t[t[k].ch[0]].lx,t[t[k].ch[0]].rx);
    }
}

int find(int k,int x)
{
    pushdown(k);
    if(t[t[k].ch[0]].size>=x)return find(t[k].ch[0],x);
    else if(t[t[k].ch[0]].size+1<x)return find(t[k].ch[1],x-1-t[t[k].ch[0]].size);
    else return k;
}

void update(int k)
{
    int l=t[k].ch[0],r=t[k].ch[1];
    t[k].size=t[t[k].ch[0]].size+t[t[k].ch[1]].size+1;
    t[k].sum=t[t[k].ch[0]].sum+t[t[k].ch[1]].sum+t[k].v;
    t[k].mx=max(t[l].mx,t[r].mx);
    t[k].mx=max(t[k].mx,t[l].rx+t[r].lx+t[k].v);
    t[k].lx=max(t[l].lx,t[l].sum+t[k].v+t[r].lx);
    t[k].rx=max(t[r].rx,t[r].sum+t[k].v+t[l].rx);
}

void axe(int x,int &k,int d)
{
    int y,z;
    y=t[x].fa,z=t[y].fa;
    if(y==k)k=x;
    else {if(t[z].ch[0]==y)t[z].ch[0]=x; else t[z].ch[1]=y;}
    t[y].fa=x,t[x].fa=z,t[t[x].ch[d]].fa=y;
    t[y].ch[d^1]=t[x].ch[d];t[x].ch[d]=y;
    update(y);update(x);
}

void splay(int x,int &k)
{
    int y,z;
    while(x!=k)
    {
        y=t[x].fa;z=t[y].fa;
        if(y!=k)
        {
            if(t[y].ch[0]==x&&t[z].ch[0]==y)axe(y,k,1);
            else if(t[y].ch[1]==x&&t[z].ch[1]==y)axe(y,k,0);
            else if(t[y].ch[1]==x&&t[z].ch[0]==y)axe(x,k,0);
            else if(t[y].ch[0]==x&&t[z].ch[1]==y)axe(x,k,1);
        }
        if(t[t[x].fa].ch[0]==x)axe(x,k,1);
        else axe(x,k,0);
    }
}

void build(int l,int r,int f)
{
    if(r<l)return;
    if(l==r)
    {
        t[l].size=1;
        t[l].v=a[l];t[l].fa=f;
        if(r<f)t[f].ch[0]=r;
        else t[f].ch[1]=r;
        t[l].sum=t[l].v;
        if(a[l]>=0)t[l].lx=t[l].rx=t[l].mx=t[l].v;
        else t[l].lx=t[l].rx=0,t[l].mx=t[l].v;
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid-1,mid);build(mid+1,r,mid);
    t[mid].v=a[mid];
    t[mid].fa=f;update(mid);
    if(mid<f)t[f].ch[0]=mid;
    else t[f].ch[1]=mid;
}

inline int getnum()
{
    int x=que[head++];
    while(ok[x]){x=que[head++];if(head==maxn)head=0;}
    if(head==maxn)head=0;
    ok[x]=1;
    return x;
}

inline void inque(int k)
{
    t[k]=E;
    ok[k]=0;tail++;
    if(tail==maxn)tail=0;
    que[tail]=k;
}

void del(int k)
{
    if(t[k].ch[0])del(t[k].ch[0]);
    if(t[k].ch[1])del(t[k].ch[1]);
    inque(k);
}

int main()
{
    int n,m,x,c,size=0;
    n=in();m=in();size=n+2;
    t[0].mx=a[1]=a[n+2]=-99999999;
    for(int i=2;i<=n+1;i++)
        a[i]=in();
    build(1,n+2,0);
    root=(n+3)>>1;
    for(int i=n+3;i<maxn;i++)que[++tail]=i;
    for(int i=1;i<=m;i++)
    {
        memset(s,0,sizeof(s));
        scanf("%s",s);
        if(s[0]=='I')
        {
            x=in();
            top=in();
            if(top==0)continue;
            int x1=find(root,x+1),x2=find(root,x+2);
            splay(x1,root);splay(x2,t[root].ch[1]);
            t[t[root].ch[1]].ch[0]=getnum();
            int now=t[t[root].ch[1]].ch[0];
            t[now].size=top;
            t[now].fa=t[root].ch[1];
            t[now].v=in();
            for(int j=1;j<top;j++)
            {
                t[now].ch[1]=getnum();
                t[t[now].ch[1]].fa=now;
                now=t[now].ch[1];
                t[now].size=top-j;
                t[now].v=in();
            }
            update(now);
            while(now!=root)
            {
                now=t[now].fa;
                update(now);
            }
            //size+=top;
            //printf("size:%d\n",size);
        }
        else if(s[0]=='D')
        {
            x=in();
            top=in();
            int x1=find(root,x),x2=find(root,x+top+1);
            splay(x1,root);splay(x2,t[root].ch[1]);
            del(t[x2].ch[0]);
            t[x2].ch[0]=0;
            update(x2);
            update(x1);
            //size-=top;
            //printf("size:%d\n",size);
        }
        else if(s[0]=='M')
        {
            if(s[2]=='K')
            {
                x=in();top=in();c=in();
                int x1=find(root,x),x2=find(root,x+top+1);
                splay(x1,root),splay(x2,t[root].ch[1]);
                t[t[x2].ch[0]].tag=1,t[t[x2].ch[0]].v=c;
                t[t[x2].ch[0]].sum=t[t[x2].ch[0]].size*c;
                int xx=t[x2].ch[0];
                if(c>=0)t[xx].mx=t[xx].lx=t[xx].rx=t[xx].sum;
                else t[xx].lx=t[xx].rx=0,t[xx].mx=t[xx].v;
                update(x2);
                update(x1);
            }
            else
            {
                printf("%d\n",t[root].mx);  
            }
        }
        else if(s[0]=='R')
        {
            x=in();top=in();
            int x1=find(root,x),x2=find(root,x+top+1);
            splay(x1,root),splay(x2,t[root].ch[1]);
            t[t[x2].ch[0]].rev^=1;
            swap(t[t[x2].ch[0]].ch[0],t[t[x2].ch[0]].ch[1]);
            swap(t[t[x2].ch[0]].lx,t[t[x2].ch[0]].rx);
            update(x2);
            update(x1);
        }
        else if(s[0]=='G')
        {
            x=in();top=in();
            int x1=find(root,x);
            int x2=find(root,x+top+1);
            splay(x1,root),splay(x2,t[root].ch[1]);
            printf("%d\n",t[t[x2].ch[0]].sum);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值