BZOJ 1500 維修序列 Splay

題目鏈接:
(http://www.lydsy.com/JudgeOnline/problem.php?id=1500)
各種區間操作,但是方法都是統一的
對於操作區間[L,R]
先把(L-1)旋轉到根節點,再把(R+1)旋轉到根的右兒子,那麼需要操作的區間[L,R]就是根的 右兒子的左兒子。
但是L==1和R==n都需要特判,非常麻煩。所以不妨在前後都加一個數字,變成N+2長度的序列,就避免了特判。
另外,對於插入操作,先把要插入的數列建成一棵新的平衡樹,在接到原來的樹上。
插入量巨大,刪除的時候要遍歷一遍子樹,回收垃圾。
注意有負數的情況,更新Max的時候非常容易忽略。

代碼:

#include<cstdio>   
#include<iostream>   
#include<cstdlib>   
#include<cmath>     
#include<vector>   

using namespace std;   
const int maxn=1000000+5;
const int inf = 0x3f3f3f3f;
int n,m,A[maxn];
int Root,tot;
int Q[maxn],rear;
int fa[maxn],ch[maxn][2],sum[maxn],size[maxn],lm[maxn],rm[maxn],Max[maxn];
int lazy[maxn],rev[maxn],val[maxn];
char op[35];

template <typename T>  
inline void _read(T &x){   
    char ch=getchar(); bool mark=false;   
    for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;   
    for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';   
    if(mark)x=-x;   
}   


inline int Newnode(int key,int father){
    int o;
    if(rear) o= Q[rear--];
    else o= ++tot;
    fa[o]= father; size[o]=1; 
    lm[o]=rm[o]=sum[o]=Max[o]=val[o]= key; 
    lazy[o]=rev[o]=0; 
    ch[o][0]=ch[o][1]=0;
    return o;
}

// splay基本操作 

inline void Maintain(int o){
    int ls= ch[o][0],rs=ch[o][1];
    size[o]= size[ls]+size[rs]+1;
    sum[o]= sum[ls]+sum[rs]+val[o];
    lm[o]= max(lm[ls],sum[ls]+val[o]+max(lm[rs],0));
    rm[o]= max(rm[rs],sum[rs]+val[o]+max(rm[ls],0));
    Max[o]= max(Max[ls],Max[rs]);
    Max[o]= max(Max[o],max(rm[ls],0)+val[o]+max(lm[rs],0));
}

int Build(int L,int R,int father){
    if(L>R) return 0;
    int mid= (L+R)>>1;
    int o = Newnode(A[mid],father);
    ch[o][0]= Build(L,mid-1,o);
    ch[o][1]= Build(mid+1,R,o);
    Maintain(o);
    return o;
}

inline void Update_val(int o,int v){
    if(!o) return;
    lazy[o]=1;val[o]=v ;
    sum[o]= size[o]*v;
    Max[o]= lm[o]= rm[o]= max(size[o]*v,v);
}

inline void Update_rev(int o){
    if(!o) return ;
    rev[o]^=1;
    swap(ch[o][0],ch[o][1]);
    swap(lm[o],rm[o]);
}

inline void pushdown(int o){
    int ls = ch[o][0],rs= ch[o][1];
    if(lazy[o]){
        Update_val(ls,val[o]); Update_val(rs,val[o]);
        lazy[o]=0;
    }
    if(rev[o]){
        Update_rev(ls); Update_rev(rs);
        rev[o]=0;
    }
}

inline void Rotate(int x,int f){
    int y=fa[x],z=fa[y];
    ch[z][ch[z][1]==y]=x; fa[x]=z;
    fa[ch[x][f]]= y; ch[y][f^1]=ch[x][f];
    ch[x][f]=y; fa[y]=x;
    Maintain(y); Maintain(x);
}

int q[maxn],tail;

inline void splay(int x,int aim){
    tail=0;
    q[++tail]=x;
    for(int i=x;i!=aim;i=fa[i]){ q[++tail]= fa[i];}
    while(tail) pushdown(q[tail--]);
    int o= fa[aim];
    while(fa[x]!=o){
        int y=fa[x],z=fa[y];
        if(z!=o){
            int f= (ch[z][1]==y);
            if(ch[y][f]==x) Rotate(y,f^1),Rotate(x,f^1);
            else Rotate(x,f),Rotate(x,f^1);
        }
        else Rotate(x,ch[y][0]==x); 
    }
    Maintain(x);
    if(!o) Root= x;
} 

int FindKth(int k){
    int cur=Root;
    while(true){
        pushdown(cur); 
        if(size[ch[cur][0]]+1==k) return cur;
        else if(size[ch[cur][0]] >= k ) cur= ch[cur][0];
        else k-= size[ch[cur][0]]+1,cur=ch[cur][1];
    }
}
// Splay ends here.
//Operations
int GetSum(int pos,int cnt){
    splay(FindKth(pos),Root);
    splay(FindKth(pos+1+cnt),ch[Root][1]);
    return sum[ch[ch[Root][1]][0]];
}

void Recycle(int o){
    Q[++rear]=  o;
    if(ch[o][0]) Recycle(ch[o][0]);
    if(ch[o][1]) Recycle(ch[o][1]);
}

void Delete(int pos,int cnt){
    splay(FindKth(pos),Root);
    splay(FindKth(pos+1+cnt),ch[Root][1]);
    int o= ch[Root][1];
    fa[ch[o][0]]=0;
    Recycle(ch[o][0]);
    fa[ch[o][0]]=0; ch[o][0]=0; 
    Maintain(o);Maintain(Root);
}

void Make_Same(int pos,int cnt,int v){
    splay(FindKth(pos),Root);
    splay(FindKth(pos+1+cnt),ch[Root][1]);
    Update_val(ch[ch[Root][1] ] [0],v);
    Maintain(ch[Root][1]); Maintain(Root);
}

void Reverse(int pos,int cnt){
    splay(FindKth(pos),Root);
    splay(FindKth(pos+1+cnt),ch[Root][1]);
    Update_rev(ch[ch[Root][1] ] [0] );
    Maintain(ch[Root][1]); Maintain(Root);
}

void Insert(){
    int pos,cnt,i;
    _read(pos); _read(cnt);
    for(i=1;i<=cnt;i++) _read(A[i]);
    splay(FindKth(pos+1),Root);
    splay(FindKth(pos+2),ch[Root][1]);
    ch[ch[Root][1]][0]= Build(1,cnt,ch[Root][1]);
    Maintain(ch[Root][1]); Maintain(Root);
}

void Max_Sum(int pos,int cnt){
    splay(FindKth(pos),Root);
    splay(FindKth(pos+1+cnt),ch[Root][1]);
    printf("%d\n",Max[ch[ch[Root][1]][0]]);
}

void Init(){
    int i;
    for(i=2;i<=n+1;i++) _read(A[i]);
    A[1]=A[n+2]= -1;
    Root= Build(1,n+2,0);
}

void put(){
    int sz= size[Root]; cout<<"Array: ";
    for(int i=1;i<=sz;i++)cout<<val[FindKth(i)]<<" ";
    cout<<endl;
}
int main(){
    //freopen("data.in","r",stdin);
    //freopen("myans.out","w",stdout);
    int i,j,x,y,c;
    _read(n); _read(m);
    for(i=0;i<maxn;i++)Max[i]= - inf ; 
    Init();
    while(m--){
        scanf("%s",op+1);
        if(op[1]=='I') Insert();
        else if(op[1]=='D'){
            _read(x); _read(y);
            Delete(x,y);
        }
        else if(op[1]=='M' && op[3]=='K'){
            _read(x); _read(y); _read(c);
            Make_Same(x,y,c);
        }
        else if(op[1]=='R'){
            _read(x); _read(y); 
            Reverse(x,y);
        }
        else if(op[1]=='G'&&op[5]=='S'){
            _read(x); _read(y);
            printf("%d\n",GetSum(x,y));
        }
        else if(op[1]=='M' && op[5]=='S')Max_Sum(1,size[Root]-2);
        //put();
    }
    return 0;
}
發佈了195 篇原創文章 · 獲贊 14 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章