【BZOJ1500】【codevs1758】维修数列,简析Splay的综合操作

Time:2016.05.12
Author:xiaoyimi
转载注明出处谢谢


传送门1
传送门2
思路:
我的天啊!
Splay大板子!
调了好久啊!
这里的Splay没有判断的key值,换一种说法,这不是一个严格的二叉查找树,只是借用了Splay的实现形式,或者说我们可以理解成key值就是它的插入顺序……
1.插入
把pos代表的节点转到根,pos+1代表的节点转到根下面(即pos的右子树),然后往pos+1左子树上插就可以了
2.删除
pos-1代表的节点转到根,pos+tot代表的节点转到根的右子树,那么pos+tot代表的节点的左子树就是我们要删除的全部节点
3.修改
和删除操作类似,这里不是删除,而是在pos+tot的左子树上类似线段树那样的打上数字标记
4.翻转
和删除、修改操作类似,打翻转标记,同时这里的翻转标记代表其所在节点的左右儿子已交换,下传时也要让左右儿子的子树交换,以此类推
5.求和
对于某一节点x,其sum为左儿子+右儿子+自身,所以直接像2,3,4操作那样转一下,输出sum即可
6.求最大连续子列
(这里的最大连续子列不能是空)
像线段树一样的记录当前节点的总最大和,左端所在最大和,右端所在最大和,上传时要仔细想想。这里我被0的问题纠结了好久,所以又维护了一个单点最大值,那么如果所求序列里全是负数,输出的就是一个最大的负数
注意:
坑点无穷!
首先你必须开一个内存池存编号啥的,不管是指针还是数组,不然插入的数 4106 不回收,64MB内存早就炸飞了
插入时把插入的序列弄成一颗平衡树再插进去,不然插入一条链是会T的
翻转区间时左右子树交换,左端最大和、右端最大和也要交换
平衡树中加两个哨兵节点,值为0,能避免很多讨论情况(比如找第k大再旋转什么的)
总最大和长度不能为0,但左、右端可以为0
每次Splay,rorate啥的都要上传下放标记……吗
当你觉得你的程序没什么问题但就是WA or TLE的时候,那就来一发紧张刺激的Splay操作
代码:

#include<bits/stdc++.h>
#define M 500005
using namespace std;
int n,m,tot,root;
int stacks[M],fa[M],son[M][2],siz[M],sum[M],pre[M],sub[M],data[M],lazy[M],maxn[M],mx[M],reads[M];
bool rev[M];
char s[11];
queue<int>q;
int in()
{
    char ch=getchar();int t=0,f=1;
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        else if (f==-1) f=1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') t=(t<<3)+(t<<1)+ch-48,ch=getchar();
    return f*t;
}
void ct(int x)
{
    int ls=son[x][0],rs=son[x][1];
    siz[x]=1+siz[ls]+siz[rs];
    sum[x]=data[x]+sum[ls]+sum[rs];
    mx[x]=max(max(mx[ls],mx[rs]),data[x]);
    maxn[x]=max(max(maxn[ls],maxn[rs]),data[x]+pre[rs]+sub[ls]);
    pre[x]=max(pre[ls],sum[ls]+data[x]+pre[rs]);
    sub[x]=max(sub[rs],sum[rs]+data[x]+sub[ls]);
}
void rever(int x){swap(son[x][0],son[x][1]);swap(pre[x],sub[x]);}
void pushdown(int x)
{
    if (!rev[x]&&lazy[x]==-1001) return;
    if (rev[x])
        rev[son[x][0]]^=1,
        rev[son[x][1]]^=1,
        rever(son[x][0]),rever(son[x][1]),
        rev[x]=0;
    if (lazy[x]!=-1001)
        lazy[son[x][0]]=lazy[x],
        sum[son[x][0]]=lazy[x]*siz[son[x][0]],
        maxn[son[x][0]]=max(sum[son[x][0]],lazy[x]),
        sub[son[x][0]]=pre[son[x][0]]=max(0,sum[son[x][0]]),
        data[son[x][0]]=data[son[x][1]]=lazy[x],
        mx[son[x][0]]=mx[son[x][1]]=lazy[x],
        lazy[son[x][1]]=lazy[x],
        sum[son[x][1]]=lazy[x]*siz[son[x][1]],
        maxn[son[x][1]]=max(sum[son[x][1]],lazy[x]),
        sub[son[x][1]]=pre[son[x][1]]=max(0,sum[son[x][1]]),
        lazy[x]=-1001;
}
int make(int x)
{
    int now=stacks[stacks[0]--];
    maxn[now]=mx[now]=data[now]=x;
    lazy[now]=-1001;rev[now]=0; 
    son[now][0]=son[now][1]=0;
    return now;
}
void rorate(int x,bool mk)
{
    int y=fa[x];
    pushdown(y);pushdown(x);
    fa[son[x][mk]]=y;son[y][!mk]=son[x][mk];
    fa[x]=fa[y];
    if (fa[y])
    {
        if (son[fa[y]][0]==y) son[fa[y]][0]=x;
        else son[fa[y]][1]=x;
    }
    fa[y]=x;son[x][mk]=y;
    ct(y);ct(x);
}
void splay(int x,int goal)
{
    int y;
    while (fa[x]!=goal)
    {
        y=fa[x];
        if (fa[y]==goal)
        {
            if (son[y][0]==x) rorate(x,1);
            else rorate(x,0);
        }
        else if (son[fa[y]][0]==y)
        {
            if (son[y][0]==x) rorate(y,1);
            else rorate(x,0);
            rorate(x,1);
        }
        else
        {
            if (son[y][1]==x) rorate(y,0);
            else rorate(x,1);
            rorate(x,0);
        }
    }
    if (!goal) root=x;
}
int Kth(int k)
{
    if (!k) return 0;
    int x=root;
    while (x)
    {
        pushdown(x);
        if (siz[son[x][0]]+1==k) return x;
        if (siz[son[x][0]]+1>k) x=son[x][0];
        else k-=siz[son[x][0]]+1,x=son[x][1];
    }
}
int build(int begin,int end)
{
    if (begin>end) return 0;
    int mid=begin+end>>1;
    int now=make(reads[mid]),ls=build(begin,mid-1),rs=build(mid+1,end);
    son[now][0]=ls;son[now][1]=rs;
    fa[ls]=fa[rs]=now;
    ct(now);
    return now;
}
main()
{
    for (int i=1;i<=M-3;i++) stacks[i]=M-3-i+1,lazy[i]=-1001;
    stacks[0]=M-3; 
    n=in();m=in();
    reads[1]=0;reads[n+2]=0;
    for (int i=2;i<=n+1;i++) reads[i]=in();
    int pos,x,c,mid=(n+3)>>1;
    root=build(1,n+2);
    tot=n+2;
    while (m--)
    {
        s[0]=getchar();
        int t=0;
        while (s[0]<'A'||s[0]>'Z')s[0]=getchar();
        while ((s[t]>='A'&&s[t]<='Z')||s[t]=='-') s[++t]=getchar();
        if (s[0]=='I')
        {
            pos=in()+1;x=in();
            tot+=x;
            splay(Kth(pos),0);
            splay(Kth(pos+1),root);
            for (int i=1;i<=x;i++) reads[i]=in();
            pos=build(1,x);
            fa[pos]=son[root][1];
            son[son[root][1]][0]=pos;
            ct(son[root][1]);ct(root);
        }
        else if (s[0]=='D')
        {
            pos=in()+1;x=in();
            tot-=x;
            splay(Kth(pos-1),0);
            splay(Kth(pos+x),root);
            pos=son[root][1];
            if (son[pos][0]) q.push(son[pos][0]),son[pos][0]=0;
            ct(pos);ct(root);
            for (;!q.empty();q.pop())
            {
                stacks[++stacks[0]]=q.front();
                if (son[q.front()][0]) q.push(son[q.front()][0]);
                if (son[q.front()][1]) q.push(son[q.front()][1]);
            }
        }
        else if (s[0]=='M'&&s[2]=='K')
            pos=in()+1,x=in(),c=in(),
            splay(Kth(pos-1),0),
            splay(Kth(pos+x),root),
            pos=son[root][1],
            data[son[pos][0]]=mx[son[pos][0]]=lazy[son[pos][0]]=c,
            sum[son[pos][0]]=c*siz[son[pos][0]],
            sub[son[pos][0]]=pre[son[pos][0]]=max(0,sum[son[pos][0]]),
            maxn[son[pos][0]]=max(sum[son[pos][0]],c),
            splay(son[pos][0],0);
        else if (s[0]=='R')
            pos=in()+1,x=in(),
            splay(Kth(pos-1),0),
            splay(Kth(pos+x),root),
            pos=son[root][1],
            rev[son[pos][0]]^=1,
            rever(son[pos][0]),
            splay(son[pos][0],0);
        else if (s[0]=='G')
            pos=in()+1,x=in(),
            splay(Kth(pos-1),0),
            splay(Kth(pos+x),root),
            printf("%d\n",sum[son[son[root][1]][0]]);
        else
        {
            splay(Kth(1),0);
            splay(Kth(tot),root);
            if(maxn[root])printf("%d\n",maxn[root]);
            else printf("%d\n",mx[son[son[root][1]][0]]);
        }
    }                           
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值