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

题目大意:

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

思路:

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

/*==================
 * Author : Ylsoi
 * Problem : spaly
 * Algorithm : lct
 * Time : 2018.4.10
 * ===============*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<set>
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 va<tt.va;
    }
};
int ch[maxn][2],fa[maxn],root,va[maxn];
set<node>s;
set<node>::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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值