zoukankan      html  css  js  c++  java
  • [BZOJ 1500] 维护序列

    Link:

    BZOJ 1500 传送门

    Solution:

    可能平衡树维护序列的所有操作都在这了吧……

    对序列的维护$fhq treap$和$Splay$都能做

    有几个注意点:

    1、维护序列时始终记得第$k$大指的是序号,与权值无关

    2、注意对0的初始化,毕竟如果无叶子结点时会用到

    3、如果数据总量过大要数据回收,用队列记录被删除的节点,同时记得将儿子信息初始化!

    4、如果求最大子序列和,一般要维护$lmx,rmx$来求解

    如果同时还有翻转操作,记得将$lmx$和$rmx$也要翻转!

    6、对$Treap$的初始化时并不需要基于随机的旋转操作,直接构造就好了

    要明白随机的旋转目的是为了保证期望树高,如果已经构造得最优了自然不必旋转了

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    #define X first
    #define Y second
    #define lc s[x][0]
    #define rc s[x][1]
    typedef long long ll;
    typedef pair<int,int> P;
    const int MAXN=5e5+10,INF=1<<30;
    char op[20];queue<int> q;
    int spin[MAXN],cov[MAXN],sum[MAXN],mx[MAXN],lmx[MAXN],rmx[MAXN];
    int rt,n,m,num,cnt,dat[MAXN],s[MAXN][2],pri[MAXN],sz[MAXN],val[MAXN];
    
    int newnode(int x)
    {
        int cur;
        if(!q.empty()) cur=q.front(),q.pop();
        else cur=++cnt;
        
        sz[cur]=1;pri[cur]=rand();
        s[cur][0]=s[cur][1]=0;//重用节点后记得清零 
        val[cur]=sum[cur]=mx[cur]=lmx[cur]=rmx[cur]=x;
        spin[cur]=0;cov[cur]=INF;return cur;
    }
    
    void rotate(int x)
    {
        swap(s[x][0],s[x][1]);
        swap(lmx[x],rmx[x]);spin[x]^=1;
    }
    void modify(int x,int k)
    {//记得更新所有数据! 
        val[x]=k;cov[x]=k;
        sum[x]=sz[x]*k;
        mx[x]=max(sum[x],val[x]);
        lmx[x]=rmx[x]=max(0,sum[x]);
    }
    void pushdown(int x)
    {
        if(spin[x])
        {if(lc) rotate(lc);if(rc) rotate(rc);}
        if(cov[x]!=INF)
        {if(lc) modify(lc,cov[x]);if(rc) modify(rc,cov[x]);}
        spin[x]=0;cov[x]=INF;
    }
    void pushup(int x)
    {
        if(!x) return;
        sz[x]=sz[lc]+sz[rc]+1;
        sum[x]=sum[lc]+sum[rc]+val[x];
        mx[x]=max(mx[lc],mx[rc]);
        mx[x]=max(mx[x],max(0,rmx[lc])+val[x]+max(0,lmx[rc]));
        lmx[x]=max(lmx[lc],sum[lc]+val[x]+max(0,lmx[rc]));
        rmx[x]=max(rmx[rc],sum[rc]+val[x]+max(0,rmx[lc]));
    }
    
    int build(int l,int r)
    {
        if(l>r) return 0;
        int mid=(l+r)>>1;
        int x=newnode(dat[mid]);
        s[x][0]=build(l,mid-1);
        s[x][1]=build(mid+1,r);
        pushup(x);return x;
    }
    void split(int x,int k,int &a,int &b)
    {
        if(!x){a=b=0;return;}
        pushdown(x);
        if(k<=sz[lc]) b=x,split(lc,k,a,lc);
        else a=x,split(rc,k-sz[lc]-1,rc,b);
        pushup(x);
    }
    int merge(int x,int y)
    {
        if(!x||!y) return x+y;
        pushdown(x);pushdown(y);
        if(pri[x]<pri[y])
        {
            s[x][1]=merge(s[x][1],y);
            pushup(x);return x;
        }
        else
        {
            s[y][0]=merge(x,s[y][0]);
            pushup(y);return y;
        }
    }
    
    void reuse(int x)
    {//记录重用节点 
        if(!x) return;
        q.push(x);
        reuse(lc);reuse(rc);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
        mx[0]=val[0]=-INF;rt=build(1,n);
        
        int num,pos,k,x,y,z;
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op+1);
            if(op[3]!='X') scanf("%d%d",&pos,&num);
            if(op[1]=='I')
            {
                for(int j=1;j<=num;j++) 
                    scanf("%d",&dat[j]);
                z=build(1,num);
                split(rt,pos,x,y);
                rt=merge(x,merge(z,y));
            }
            else if(op[1]=='D')
            {
                split(rt,pos-1,x,y);
                split(y,num,y,z);
                reuse(y);rt=merge(x,z);
            }
            else if(op[3]=='K')
            {
                scanf("%d",&k);
                split(rt,pos-1,x,y);
                split(y,num,y,z);
                modify(y,k);
                rt=merge(x,merge(y,z));
            }
            else if(op[1]=='R')
            {
                split(rt,pos-1,x,y);
                split(y,num,y,z);rotate(y);
                rt=merge(x,merge(y,z));
            }
            else if(op[1]=='G')
            {
                split(rt,pos-1,x,y);
                split(y,num,y,z);
                printf("%d
    ",sum[y]);
                rt=merge(x,merge(y,z));
            }
            else printf("%d
    ",mx[rt]);
        }
        return 0;
    }
  • 相关阅读:
    二部图(二分图判定--dfs)
    chd校内选拔赛题目+题解
    敌兵布阵 线段树单点更新
    Employment Planning DP
    Tickets 基础DP
    Super Jumping! Jumping! Jumping! 基础DP
    【高精度加法】
    【最短路径之dijkstra(迪杰斯特拉)算法】
    各类最短路算法基本模板-C++
    【最小生成树之Prim算法】-C++
  • 原文地址:https://www.cnblogs.com/newera/p/9637495.html
Copyright © 2011-2022 走看看