洛谷 P2042[NOI2005]维护数列 (平衡树)

传送门

平衡树裸题

为了熟悉一下平衡树,来做了一下这道码农题,
虽然辛苦,但确实对 \(FhqTreap\) 的理解加深了不少。
下面贴上没有优化,开了 \(O2\) 和各种卡常勉强过去的代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
using namespace std;
typedef long long LL;
const int MAXN=5000010;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
int n,m;

inline int read(){
    int x=0,f=1;char c=getchar();
    while(c<'0'||c>'9') {if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    return x*f;
}

struct FhqTreap{
    int L[MAXN],R[MAXN],tag[MAXN],rev[MAXN],siz[MAXN],key[MAXN],tot,root;
    int val[MAXN],sum[MAXN],lx[MAXN],rx[MAXN],mx[MAXN];

    inline int newnode(int value){
        //cout<<value<<endl;
        tag[++tot]=inf,val[tot]=value,sum[tot]=value,siz[tot]=1,key[tot]=rand();
        if(value>0) lx[tot]=rx[tot]=mx[tot]=value;
        else lx[tot]=rx[tot]=0,mx[tot]=value;
        return tot;
    }

    inline void pushdown(int id){
        if(tag[id]!=inf){
            sum[L[id]]=tag[id]*siz[L[id]],val[L[id]]=tag[L[id]]=tag[id];
            sum[R[id]]=tag[id]*siz[R[id]],val[R[id]]=tag[R[id]]=tag[id];
            if(tag[id]>0) 
                lx[L[id]]=rx[L[id]]=mx[L[id]]=sum[L[id]],
                lx[R[id]]=rx[R[id]]=mx[R[id]]=sum[R[id]];
            else
                lx[L[id]]=rx[L[id]]=lx[R[id]]=rx[R[id]]=0,
                mx[L[id]]=mx[R[id]]=tag[id];
            tag[id]=inf;
            rev[id]=0;
        }
        if(rev[id]){
            swap(L[L[id]],R[L[id]]),swap(lx[L[id]],rx[L[id]]);
            swap(L[R[id]],R[R[id]]),swap(lx[R[id]],rx[R[id]]);
            rev[L[id]]^=1,rev[R[id]]^=1;
            rev[id]=0;
        }
    }

    inline void pushup(int id){
        siz[id]=siz[L[id]]+siz[R[id]]+1;
        sum[id]=sum[L[id]]+sum[R[id]]+val[id];
        lx[id]=max(lx[L[id]],sum[L[id]]+val[id]+lx[R[id]]);
        rx[id]=max(rx[R[id]],sum[R[id]]+val[id]+rx[L[id]]);
        mx[id]=max(max(mx[L[id]],mx[R[id]]),rx[L[id]]+lx[R[id]]+val[id]);
    }

    inline void split(int id,int size,int &x,int &y){
        if(!id) x=y=0;
        else{
            pushdown(id);
            if(size>siz[L[id]])
                x=id,split(R[id],size-siz[L[id]]-1,R[id],y);
            else   
                y=id,split(L[id],size,x,L[id]);
            pushup(id);
        }
    }

    inline int merge(int x,int y){
        if(!x||!y) return x+y;
        if(key[x]>key[y]){
            pushdown(x);
            R[x]=merge(R[x],y);
            pushup(x);
            return x;
        }
        else{
            pushdown(y);
            L[y]=merge(x,L[y]);
            pushup(y);
            return y;
        }
    }

    inline void insert(){
        int ins=0,pos=read(),num=read();
        for(register int i=1;i<=num;i++) ins=merge(ins,newnode(read()));
        int x,y;
        split(root,pos,x,y);
        root=merge(merge(x,ins),y);
    }

    inline void del(){
        int pos=read(),num=read();
        int x,y,z;
        split(root,pos-1,x,y);
        split(y,num,y,z);
        root=merge(x,z);
    }

    inline void update(){
        int pos=read(),num=read(),value=read();
        int x,y,z;
        split(root,pos-1,x,y);
        split(y,num,y,z);
        sum[y]=1ll*value*siz[y];
        val[y]=tag[y]=value;
        if(value>0) lx[y]=rx[y]=mx[y]=sum[y];
        else lx[y]=rx[y]=0,mx[y]=value;
        root=merge(merge(x,y),z);
    }

    inline void reverse(){
        int pos=read(),num=read();
        int x,y,z;
        split(root,pos-1,x,y);
        split(y,num,y,z);
        rev[y]^=1;
        swap(L[y],R[y]),swap(lx[y],rx[y]);
        root=merge(merge(x,y),z);
    }

    inline void getsum(){
        int pos=read(),num=read(),x,y,z;
        split(root,pos-1,x,y);
        split(y,num,y,z);
        printf("%d\n",sum[y]);
        root=merge(merge(x,y),z);
    }

    inline void maxsum(){
        printf("%d\n",mx[root]);
    }
}fhq;


int main(){
    srand(time(0));
    n=read(),m=read();
    for(register int i=1;i<=n;i++)
        fhq.root=fhq.merge(fhq.root,fhq.newnode(read()));
    char opt[20];
    while(m--){
        scanf("%s",opt);
        if(opt[0]=='I') fhq.insert();
        else if(opt[0]=='D') fhq.del();
        else if(opt[0]=='R') fhq.reverse();
        else if(opt[0]=='G') fhq.getsum();
        else if(opt[0]=='M'&&opt[2]=='K') fhq.update();
        else if(opt[0]=='M'&&opt[2]=='X') fhq.maxsum();
    }
    return 0;
}

其实数组容量不需要开那么大, 有点太极限了, 贴着内存限制过去的
题面上说了, 同时在数列中的数不超过 \(5\cdot 10^5\) 那么可以搞一个 \(queue\),
把删除之后的节点编号放进去, 就像一个内存回收器一样.

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/11774869.html