【LuoguP3721】[HNOI2017]单旋

题目链接

题目描述

详细请自己去看题面。

题意:
对于一颗只能进行单旋操作的splay(题中叫spaly),有如下四个操作:
1.插入一个节点,代价为插入后节点的深度。
2.把最小值旋到根,代价为其原来的深度。
3.把最大值旋到根,代价为其原来的深度。
4.进行2操作后把根节点删掉。
5.进行3操作后把根节点删掉。

题解

一道看起来有点滑稽的题,显然不是用splay做啦 OVO
一看只要旋最大值和最小值,那么旋的时候肯定是一条链上去啦。
再手玩一下,发现转了后树的形态基本没变,只是把最小值(最大值)的右儿子(左儿子)接到父节点的左儿子(右儿子)上,再直接把该节点放到根上就OK啦。

深度怎么求呢? LCT即可,维护size。
插入呢,难道O(logn)?(显然实际是O(n)),发现好像是前驱和后继中深度大的那个点。set搞起。
但是还有一个问题,原splay中的树的形态是必须要维护的,因为不然就不知道怎么cut了。

#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
inline int read()
{
    int x=0;char ch=getchar();int t=1;
    for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    return x*t;
}
const int N=1e5+10;
#define __ NULL
#define Pr pair
#define fi first
#define se second
#define ls son[0]
#define rs son[1]
#define get_size(a) (a==__? 0:a->size)
#define get_son(a) (a->fa->rs==a)
struct node{
    node* fa;node* son[2];bool is_root;bool rev;int size;
    inline void clear(){fa=ls=rs=__;size=1;rev=0;is_root=1;}
}*tr[N];
int root;
node pool[N];int cnt=0;
int m;
node* st[N];
int Fa[N];
int LS[N];
int RS[N];//用于维护实际Spaly的形态
inline void updata(node* p){if(p==__) return;p->size=1+get_size(p->ls)+get_size(p->rs);}
inline void push_down(node* p)
{
    if(p==__||p->rev==0) return;p->rev=0;
    if(p->ls!=__) p->ls->rev^=1;
    if(p->rs!=__) p->rs->rev^=1;
    swap(p->ls,p->rs);
}
void push(node* p){int top;st[top=1]=p;while(!p->is_root) st[++top]=(p=p->fa);while(top) push_down(st[top--]);}
inline void rotate(node* p)
{
    if(p==__||p->is_root) return;
    register node* q=p->fa;register node* gp=q->fa;
    register int k=get_son(p);
    q->son[k]=p->son[k^1];
    if(p->son[k^1]!=__) p->son[k^1]->fa=q;p->fa=gp;
    if(q->is_root) q->is_root=0,p->is_root=1;
    else if(gp!=__) gp->son[get_son(q)]=p;
    q->fa=p;p->son[k^1]=q;
    updata(q);
    return;
}
inline void Splay(node* p)
{
    if(p==__) return;push(p);
    for(;!p->is_root;rotate(p)){
        if(p->fa->is_root) continue;
        if(get_son(p)==get_son(p->fa)) rotate(p->fa);
        else rotate(p);
    }
    updata(p);
}
inline void access(node* p)
{
    for(register node* pre=__;p!=__;pre=p,p=p->fa){
        Splay(p);if(p->rs!=__) p->rs->is_root=1;p->rs=pre;
        if(pre!=__) pre->is_root=0;updata(p);
    }
}
inline void m_root(node* p){access(p);Splay(p);p->rev^=1;}
inline void split(node* p,node* q){m_root(p);access(q);Splay(q);}
inline void Link(node* p,node* q){m_root(p);p->fa=q;}
inline void Cut(node* p,node* q){split(p,q);if(q->ls==p) p->fa=q->ls=__,p->is_root=1,updata(q);}
set S;
set::iterator it;
int ans=0;
inline int Dep(node* p,node* q){split(p,q);return q->size;}
inline void Add(int x)
{
    ++cnt;tr[cnt]=&pool[cnt];tr[cnt]->clear();
    Pr p=Pr(x,cnt);
    if(S.empty())   {S.insert(p);root=cnt;ans=1;return;}
    int a=0;x=0;int b=0,y=0;
    it=S.insert(p).fi;
    if(it!=S.begin()) {p=*(--it);a=p.se;x=Dep(tr[root],tr[a]);++it;}
    ++it;
    if(it!=S.end()) {p=*it;b=p.se;y=Dep(tr[root],tr[b]);}
    if(x>y) Fa[cnt]=a,RS[a]=cnt,Link(tr[a],tr[cnt]);//接在前驱和后继中深度较大的点上
    else Fa[cnt]=b,LS[b]=cnt,Link(tr[b],tr[cnt]);
    ans=Dep(tr[root],tr[cnt]);
}
inline void splay(int u,int op,bool del)
{
    if(u==root) {
        if(op==1&&del){
            S.erase(S.begin());
            Cut(tr[u],tr[RS[u]]);
            root=RS[u];Fa[root]=RS[u]=0;
        }
        else if(op==2&&del){
            S.erase(--S.end());
            Cut(tr[u],tr[LS[u]]);
            root=LS[u];Fa[root]=LS[u]=0;
        }
        ans=1;return;
    }
    node* p=tr[u];
    ans=Dep(tr[root],p);
    register int v=Fa[u];
    if(op==1){
        LS[v]=RS[u];Fa[u]=0;
        if(RS[u]) Cut(tr[u],tr[RS[u]]),Link(tr[v],tr[RS[u]]),Fa[RS[u]]=v,RS[u]=0;
        Cut(tr[u],tr[v]);
        if(!del){Link(tr[u],tr[root]);Fa[root]=u;RS[u]=root;root=u;}
        else S.erase(*S.begin());
    }
    else{
        RS[v]=LS[u];Fa[u]=0;
        if(LS[u]) Cut(tr[u],tr[LS[u]]),Link(tr[v],tr[LS[u]]),Fa[LS[u]]=v,RS[u]=0;
        Cut(tr[u],tr[v]);
        if(!del){Link(tr[u],tr[root]);Fa[root]=u;LS[u]=root;root=u;}
        else S.erase(*(--S.end()));
    }
}
int main()
{
    m=read();
    register int op;
    for(register int i=1;i<=m;i++){
        op=read();
        if(op==1) Add(read());
        else if(op==2) splay((*S.begin()).se,1,0);
        else if(op==3) splay((*(--S.end())).se,2,0);
        else if(op==4) splay((*S.begin()).se,1,1);
        else if(op==5) splay((*(--S.end())).se,2,1);
        printf("%d\n",ans);
    }
}

你可能感兴趣的:(======题解======,LCT(动态树),HNOI)