splay区间操作(bzoj1500)

传送门

其实这道题思路还是满简单的,只是代码量和debug让人感到痛苦,但还是蛮锻炼能力的


还是说说各个操作

插入

不同普通题的是,插入是插入一段。如果一个一个插的话会很慢,我们可以先把要插入的一段建成一个平衡树,再一起插入。

删除

删除也是删除一段区间[L,R],我们可以把L-1旋转到根,R+1旋转到根的右儿子,那么[L,R]就在根的右儿子的左二子,删除就可以了。

注意:每次删除的点是可以进行回收再利用的(节省空间)

修改

修改一段区间打上标记就好。

翻转

同样的打标记(而且和修改的标记是不影响的),可参考文艺平衡树

求和

其实就类似于线段树的求和,节点维护sum就好了

求和最大的子列

我们在每个节点会维护3个信息,lx最大前缀,rx最大后缀,maxx最大子列

pushup时注意一下更新的方法就好

#include<bits/stdc++.h>
#define INF 2100000001
#define N 500003
#define M 4000003
#define LL long long
using namespace std;
int read()
{
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
int root,ndnum=0;
char s[12];
int a[N];
int ch[N][3],rev[N],tag[N],siz[N],f[N],key[N];
LL sum[N],lx[N],rx[N],maxx[N];
queue<int>q;
int get(int x)
{
    return ch[f[x]][1]==x;
}
void update(int x)
{
    if(!x)return ;
    int l=ch[x][0],r=ch[x][1];
    siz[x]=siz[l]+siz[r]+1;
    sum[x]=sum[l]+sum[r]+key[x];
    lx[x]=max(lx[l],sum[l]+key[x]+max((LL)0,lx[r]));
    rx[x]=max(rx[r],sum[r]+key[x]+max((LL)0,rx[l]));
    maxx[x]=max( max(rx[l],(LL)0)+key[x]+max(lx[r],(LL)0) ,max(maxx[l],maxx[r]));
}
int build(int fa,int l,int r)
{
    if(l>r)return 0;
    int mid=(l+r)>>1,now;
    if(q.empty())
    now=++ndnum;
    else 
    {
        now=q.front();q.pop();
    }
    key[now]=a[mid];
    f[now]=fa;tag[now]=-INF;sum[now]=0;siz[now]=1;
    rev[now]=0;//这些标记在新用和回收的之后一定要清空而不能有冗余 
    ch[now][0]=build(now,l,mid-1);
    ch[now][1]=build(now,mid+1,r);
    update(now);//printf(">>>%d %lld\n",now,maxx[now]);//printf("###%d\n",sum[now]);
    return now;
}
void modify(int k,int c)
{
    if(!k)return;
    tag[k]=key[k]=c;
    sum[k]=siz[k]*c;
    maxx[k]=rx[k]=lx[k]=max(sum[k],(LL)c);//如果是改成负数,最大只选一个,不然最大应该是和 
}
void turn(int k)
{
    if(!k) return;
    rev[k]^=1;
    swap(ch[k][0],ch[k][1]);
    swap(lx[k],rx[k]);
}
void pushdown(int k)
{
    if(!k) return;
    if(tag[k]!=-INF)
    {
        modify(ch[k][0],tag[k]);
        modify(ch[k][1],tag[k]);
        tag[k]=-INF;
    }
    if(rev[k])
    {
        turn(ch[k][0]);
        turn(ch[k][1]);
        rev[k]=0;
    }
}
void rotate(int x)
{
    int old=f[x];int oldf=f[old];
    int which=get(x);
    ch[old][which]=ch[x][which^1];
    f[ch[old][which]]=old;
    ch[x][which^1]=old;f[old]=x;
    f[x]=oldf;
    if(oldf) ch[oldf][ch[oldf][1]==old]=x;
    update(old);update(x);
}
void splay(int x,int tar)
{
    for(int fa;(fa=f[x])!=tar;rotate(x))
      if(f[fa]!=tar)
        rotate((get(fa)==get(x))?fa:x);
    if(!tar) root=x;  
    pushdown(root);
}
void qing(int &x)
{
    if(!x)return;
    f[x]=0;
    qing(ch[x][0]);qing(ch[x][1]);
    lx[x]=rx[x]=maxx[x]=-INF;
    siz[x]=0;
    tag[x]=-INF;rev[x]=0;sum[x]=0; 
    q.push(x);
    ch[x][0]=ch[x][1]=0;
x=0;
} 
int find(int x)
{
    int now=root;
    while(1)
    {
        pushdown(now);
        if(x<=siz[ch[now][0]]) now=ch[now][0];
        else
        {
            x-=siz[ch[now][0]]+1;
            if(!x) return now;
            now=ch[now][1];
        }
    }
}
LL query_sum(int k)
{
    return sum[k];
}
int main()
{
//    freopen("bzoj.out","w",stdout);
    int n=read(),m=read();
    for(int i=1;i<=n;++i)a[i+1]=read();
    a[1]=-INF;a[n+2]=-INF;//哨兵节点 
    rx[0]=lx[0]=maxx[0]=-INF;
    root=build(0,1,n+2);
    for(int i=1;i<=m;++i)
    {
        scanf("%s",s);
        if(s[0]=='I')
        {
            memset(a,0,sizeof(a));
            int pos=read(),tot=read();
            for(int j=1;j<=tot;++j)
              a[j]=read();
            int tmp=build(-1,1,tot);
            int x=find(pos+1),y=find(pos+2);
            splay(x,0);splay(y,x);
            f[tmp]=y;ch[y][0]=tmp;
            update(y);update(x);
        }
        if(s[0]=='D')
        {
            int pos=read(),tot=read();
            int x=find(pos),y=find(pos+tot+1);
            splay(x,0);splay(y,x);
            qing(ch[y][0]);
            update(y);update(x);
        }
        if(s[0]=='M'&&s[2]=='K')
        {
            int pos=read(),tot=read(),c=read();
            int x=find(pos),y=find(pos+tot+1);
            splay(x,0);splay(y,x);
            modify(ch[y][0],c);
            update(y);update(x);
        }
        if(s[0]=='R')
        {
            int pos=read(),tot=read();
            int x=find(pos),y=find(pos+tot+1);
            splay(x,0);splay(y,x);
            turn(ch[y][0]);
            update(y);update(x);
        }
        if(s[0]=='G')
        {
            int pos=read(),tot=read();
            int x=find(pos),y=find(pos+tot+1);
            splay(x,0);splay(y,x);
            update(y);update(x);
            printf("%lld\n",sum[ch[y][0]]);
        }   
        if(s[0]=='M'&&s[2]=='X')
        {
            printf("%lld\n",maxx[root]);
        }
    }
}
bzoj1500

特别想说一下哨兵节点,就是让我wa了很久的原因,因为题目要求求出maxx,为了不影响答案,我们把前面的和后面的哨兵都设成-INF

因为最后输出最大子列时输出root的maxx就好

posted @ 2019-07-24 19:38  yyys  阅读(368)  评论(0编辑  收藏  举报