[Hnoi2017]单旋——lct维护路径长度

题目大意:

给定一颗单旋的spaly,有5种操作,每次询问操作节点的深度。传送门

思路:

由于单选得是最小值或者最大值,所以不难发现,最小值或最大值到根的路径必定全部都是左旋或右旋,手玩几组就会发现变化的点实际上不是很多,这样对于这个点的的单旋就可以直接暴力连边。对于插入这个操作,我们考虑平衡树的一个性质,即每一个点在插入的时候都是插入到前驱的右儿子或者是后继的左儿子,所以我们又要支持一个查找前驱后继的操作,用一颗平衡树就可以了,当然用set也可以。最后考虑怎么得到答案,发现答案(深度)即为从该点到根节点的距离,并且不断地动态更新整棵树的结构,所以可以再用一颗link cut tree来维护。
不得不说代码是真的难调。。。

/*==================
 * Author : Ylsoi
 * Problem : spaly
 * Algorithm : lct
 * Time : 2018.4.10
 * ===============*/
#include
#include
#include
#include
#include
#include
using namespace std;
void File(){
    freopen("[HNOI2017]spaly.in","r",stdin);
    freopen("[HNOI2017]spaly.out","w",stdout);
}
#define REP(i,a,b) for(register int i=a;i<=b;++i)
#define DREP(i,a,b) for(register int i=a;i>=b;--i)
#define MREP(i,x) for(register int i=beg[x];i;i=E[i].last)
#define ll long long
#define inf (0x3f3f3f3f)
const int maxn=1e5+10;
int m,cnt;
struct lct{
#define lc ch[rt][0]
#define rc ch[rt][1]
#define rel(x) (ch[fa[x]][1]==x)
    int fa[maxn],size[maxn],ch[maxn][2],q[maxn],top;
    bool tag[maxn];
    void pushdown(int rt){if(tag[rt])tag[rt]=0,tag[lc]^=1,tag[rc]^=1,swap(lc,rc);}
    void pushup(int rt){size[rt]=size[lc]+size[rc]+1;}
    bool isrt(int rt){return ch[fa[rt]][0]!=rt && ch[fa[rt]][1]!=rt;}
    void rotate(int rt){
        int f=fa[rt],r=rel(rt);
        fa[rt]=fa[f];if(!isrt(f))ch[fa[f]][rel(f)]=rt;
        fa[ch[rt][r^1]]=f;ch[f][r]=ch[rt][r^1];
        fa[f]=rt;ch[rt][r^1]=f;
        pushup(f);pushup(rt);
    }
    void splay(int rt){
        top=1;q[top]=rt;
        int u=rt;
        while(!isrt(u))u=fa[u],q[++top]=u;
        DREP(i,top,1)pushdown(q[i]);
        while(!isrt(rt)){
            int f=fa[rt];
            if(!isrt(f))rotate(rel(f)==rel(rt) ? f : rt);
            rotate(rt);
        }
    }
    void access(int rt){for(int las=0;rt;las=rt,rt=fa[rt])splay(rt),rc=las,pushup(rt);}
    void makert(int rt){access(rt);splay(rt);tag[rt]^=1;}
    int findrt(int rt){access(rt);splay(rt);while(lc)rt=lc;return rt;}
    bool con(int x,int y){makert(x);return findrt(y)==x;}
    void split(int x,int y){makert(x);access(y);splay(y);}
    void link(int x,int y){makert(x);fa[x]=y;}
    void cut(int x,int y){split(x,y);if(ch[y][0]==x)ch[y][0]=0,fa[x]=0,pushup(y);}
    int query(int x,int y){split(x,y);return size[y];}
}T;
struct node{
    int va,id;
    bool operator < (const node &tt) const {
        return vaint ch[maxn][2],fa[maxn],root,va[maxn];
sets;
set::iterator it;
int Insert(int x){
    if(!s.size()){
        ++cnt;
        s.insert((node){x,cnt});
        T.size[cnt]=1;
        root=cnt;
        va[cnt]=x;
        return 1;
    }
    it=s.lower_bound((node){x,0});
    if(it!=s.begin() && !ch[(--it)->id][1]){
        ++cnt;
        s.insert((node){x,cnt});
        ch[it->id][1]=cnt;
        fa[cnt]=it->id;
        va[cnt]=x;
        T.size[cnt]=1;
        T.link(it->id,cnt);
        return T.query(root,cnt);
    }
    else{
        it=s.upper_bound((node){x,0});
        ++cnt;
        s.insert((node){x,cnt});
        ch[it->id][0]=cnt;
        fa[cnt]=it->id;
        T.size[cnt]=1;
        va[cnt]=x;
        T.link(it->id,cnt);
        return T.query(root,cnt);
    }
}
int change(bool ty){
    int id=(ty ? --s.end() : s.begin())->id;
    int ret=T.query(root,id);
    int son=ch[id][ty^1];
    if(id==root)return ret;
    if(son)T.cut(id,son),T.link(son,fa[id]);
    T.cut(id,fa[id]);
    T.link(id,root);
    ch[fa[id]][ty]=son;
    if(son)fa[son]=fa[id];
    ch[id][ty^1]=root;
    fa[root]=id;root=id;
    fa[id]=0;
    return ret;
}
int del(bool ty){
    int ret=change(ty);
    int son=ch[root][ty^1];
    s.erase((node){va[root],root});
    if(!son){root=0;return ret;}
    T.cut(root,son);
    fa[son]=0;ch[root][ty^1]=0;
    root=son;
    return ret;
}
int main(){
    File();
    scanf("%d",&m); 
    REP(i,1,m){
        int key,x;
        scanf("%d",&key);
        if(key==1){
            scanf("%d",&x);
            printf("%d\n",Insert(x));
        }
        else if(key==2)printf("%d\n",change(0));
        else if(key==3)printf("%d\n",change(1));
        else if(key==4)printf("%d\n",del(0));
        else printf("%d\n",del(1));
    }
    return 0;
}

你可能感兴趣的:(splay,动态树)