zoukankan      html  css  js  c++  java
  • 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
    ",now,maxx[now]);//printf("###%d
    ",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
    ",sum[ch[y][0]]);
            }   
            if(s[0]=='M'&&s[2]=='X')
            {
                printf("%lld
    ",maxx[root]);
            }
        }
    }
    bzoj1500

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

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

  • 相关阅读:
    事务1-JDBC事务管理
    Tomcat地址栏传中文参数乱码问题处理
    hibernate报错:org.hibernate.MappingException: No Dialect mapping for JDBC type: -1
    UVA12170 Easy Climb
    [POI2004]旅行问题
    [SCOI2010]股票交易
    [USACO11OPEN] Mowing the Lawn G
    查看文件个数 ls |wc -l
    【zombie】如何查看并杀死僵尸进程?
    [Windows] 屏幕截图
  • 原文地址:https://www.cnblogs.com/yyys-/p/11240381.html
Copyright © 2011-2022 走看看