[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\n",sum[y]);
            rt=merge(x,merge(y,z));
        }
        else printf("%d\n",mx[rt]);
    }
    return 0;
}

 

posted @ 2018-09-13 09:13  NewErA  阅读(281)  评论(0编辑  收藏  举报