Luogu3721[AH2017/HNOI2017]单旋

Luogu3721[AH2017/HNOI2017]单旋

题面:洛谷

解析:

考虑模拟题中所述单旋过程,会发现对于一次旋转的操作,就是把它的儿子和父亲接起来,把它置为当前根的父亲,成为新根,用LCT维护即可,而对于插入操作,开一个\(set\),查询前驱后继即可,代码细节较多。

代码

// luogu-judger-enable-o2
#include<set>
#include<map>
#include<cstdio>
#include<cstring>
#define I inline void
#define lc c[x][0]
#define rc c[x][1]
#define N 100005
using namespace std;
int m;
set<int> Set;
map<int,int> mp;
int c[N][2],f[N],r[N],sz[N];
inline int In(){
    char c=getchar(); int x=0,ft=1;
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') ft=-1;
    for(;c>='0'&&c<='9';c=getchar()) x=x*10+c-'0';
    return x*ft;
}
inline bool nrt(int x){
    return c[f[x]][0]==x||c[f[x]][1]==x;
}
I PushUp(int x){
    sz[x]=sz[lc]+sz[rc]+1;
}
I PushDown(int x){
    if(r[x]){ swap(lc,rc); r[lc]^=1; r[rc]^=1; r[x]=0; }
}
I rotate(int x){
    int y=f[x],z=f[y],k=c[y][1]==x,w=c[x][!k];
    if(nrt(y)) c[z][c[z][1]==y]=x; c[x][!k]=y; c[y][k]=w;
    if(w) f[w]=y; f[y]=x; f[x]=z; PushUp(y);
}
I PushAll(int x){
    if(nrt(x)) PushAll(f[x]);
    PushDown(x);
}
I splay(int x){
    PushAll(x); int y;
    while(nrt(x)){
        if(nrt(y=f[x])) rotate((c[f[y]][1]==y)^(c[y][1]==x)?x:y);
        rotate(x);
    }
    PushUp(x);
}
I access(int x){
    for(int y=0;x;x=f[y=x]) splay(x),rc=y,PushUp(x);
}
I makeroot(int x){
    access(x); splay(x); r[x]^=1;
}
I split(int x,int y){
    makeroot(x); access(y); splay(y);
}
I link(int x,int y){
    makeroot(x); f[x]=y;
}
I cut(int x,int y){
    split(x,y); f[x]=c[y][0]=0; PushUp(y);
}
int rt,tot=0,fa[N],ls[N],rs[N];
I Splay_insert(int x){
    int p=++tot; mp[x]=p;
    if(Set.empty()){ Set.insert(x); rt=p; puts("1"); return; }
    set<int> :: iterator it=Set.upper_bound(x);
    if(it==Set.end()||ls[mp[*it]]){
        --it; int k=mp[*it]; fa[p]=k; rs[k]=p; link(p,k);
    }
    else{ int k=mp[*it]; fa[p]=k; ls[k]=p; link(p,k); }
    Set.insert(x); split(p,rt); printf("%d\n",sz[rt]);
}
I Splay_min(){
    set<int> :: iterator it=Set.begin();
    int p=mp[*it]; if(p==rt){ puts("1"); return; }
    split(p,rt); printf("%d\n",sz[rt]);
    cut(p,fa[p]); if(rs[p]) cut(p,rs[p]),link(rs[p],fa[p]);
    ls[fa[p]]=rs[p]; if(rs[p]) fa[rs[p]]=fa[p];
    link(p,rt); fa[rt]=p; fa[p]=0; rs[p]=rt; rt=p;
}
I Splay_max(){
    set<int> :: iterator it=--Set.end();
    int p=mp[*it]; if(p==rt){ puts("1"); return; }
    split(p,rt); printf("%d\n",sz[rt]);
    cut(p,fa[p]); if(ls[p]) cut(p,ls[p]),link(ls[p],fa[p]);
    rs[fa[p]]=ls[p]; if(ls[p]) fa[ls[p]]=fa[p];
    link(p,rt); fa[rt]=p; fa[p]=0; ls[p]=rt; rt=p;
}
I Del_min(){
    set<int> :: iterator it=Set.begin();
    int p=mp[*it];
    if(p==rt){
        if(rs[rt]) cut(rt,rs[rt]);
        rt=rs[rt]; fa[rt]=0;
        Set.erase(it); puts("1"); return;
    }
    split(p,rt); printf("%d\n",sz[rt]);
    cut(p,fa[p]); if(rs[p]) cut(p,rs[p]),link(rs[p],fa[p]);
    ls[fa[p]]=rs[p]; if(rs[p]) fa[rs[p]]=fa[p]; Set.erase(it);
}
I Del_max(){
    set<int> :: iterator it=--Set.end();
    int p=mp[*it];
    if(p==rt){
        if(ls[rt]) cut(rt,ls[rt]);
        rt=ls[rt]; fa[rt]=0;
        Set.erase(it); puts("1"); return;
    }
    split(p,rt); printf("%d\n",sz[rt]);
    cut(p,fa[p]); if(ls[p]) cut(p,ls[p]),link(ls[p],fa[p]);
    rs[fa[p]]=ls[p]; if(ls[p]) fa[ls[p]]=fa[p]; Set.erase(it);
}
int main(){
    m=In();
    for(int i=1,op,key;i<=m;++i){
        op=In();
        if(op==1) key=In(),Splay_insert(key);
        if(op==2) Splay_min();
        if(op==3) Splay_max();
        if(op==4) Del_min();
        if(op==5) Del_max();
    }
    return 0;
}
posted @ 2019-03-12 22:04  pkh68  阅读(135)  评论(0编辑  收藏  举报