题面
题意
给出一棵树,每个点有一个优先级,初始为自己的标号,如果每次删去树上优先级最低的叶子,将得到一个序列,要求维护有三种操作:
1.将一个点的优先级修改为此时所有点的优先级的最大值+1
2.询问某个点在序列中的位置
3.询问两个点中哪一个点先被删去
做法
首先第三种操作只要经过两次二操作即可得到,因此不用管它。
观察一下第一种操作之后对序列的影响,发现第一次操作就相当于把原来最大节点到修改节点的路径上的所有点放到最后,其余不变。
可以考虑用LCT来维护,如果一个splay中所有点的中序遍历为a,b,c,d,e,就表示当点e被删去之后,点d,c,b,a将被依次连续被删去,这样就可以通过计算左子树的大小(在计算点被splay到当前根节点后)来计算在同一个splay中在它之后被删的点,对于不同splay的点,肯定是全部在它之前被删或全部在它之后被删,这样只要给每一个splay一个标号(初始为该splay中的标号最大值),用权值树状数组维护有几个点的标号比它小即可,每次access顺便在树状数组上修改一下各个权值的数量
代码
#include<bits/stdc++.h>
#define N 200100
using namespace std;
int n,m,tt,bj[N],son[N][2],size[N],fa[N];
char str[10];
bool fz[N],dwn[N];
struct Sz
{
int num[N<<1];
inline int lb(int u){return u&(-u);}
inline int add(int u,int v){for(;u<=(n+m);u+=lb(u)) num[u]+=v;}
inline int ask(int u){int res=0;for(;u;u-=lb(u)) res+=num[u];return res;}
}sz;
vector<int>to[N];
inline bool ar(int u){return u!=son[fa[u]][0]&&u!=son[fa[u]][1];}
inline bool as(int u){return u==son[fa[u]][1];}
inline void up(int now)
{
int L=son[now][0],R=son[now][1];
size[now]=size[L]+size[R]+1;
}
inline void down(int now)
{
int L=son[now][0],R=son[now][1];
if(fz[now])
{
swap(son[now][0],son[now][1]);
fz[L]^=1,fz[R]^=1;
fz[now]=0;
}
if(dwn[now])
{
bj[L]=bj[R]=bj[now];
dwn[L]=dwn[R]=1;
dwn[now]=0;
}
}
inline void rot(int u)
{
int p=fa[u],d=as(u);
if(!ar(p)) son[fa[p]][as(p)]=u;
fa[u]=fa[p];
fa[p]=u;
fa[son[u][!d]]=p;
son[p][d]=son[u][!d];
son[u][!d]=p;
up(p),up(u);
}
void Down(int now)
{
if(!ar(now)) Down(fa[now]);
down(now);
}
inline void splay(int u)
{
Down(u);
for(;!ar(u);)
{
int p=fa[u];
if(!ar(p))
as(u)==as(p)?rot(p):rot(u);
rot(u);
}
}
inline void acc(int u,int v)
{
int p,q;
for(p=u,q=0;p;q=p,p=fa[p])
{
splay(p);
son[p][1]=0,up(p);
sz.add(bj[p],-size[p]),sz.add(v,size[p]);
son[p][1]=q,up(p);
bj[p]=v,dwn[p]=1;
}
}
void dfs(int now,int last)
{
int i,t;
bj[now]=now;
for(i=0;i<to[now].size();i++)
{
t=to[now][i];
if(t==last) continue;
fa[t]=now;
dfs(t,now);
if(bj[t]>bj[now])
{
bj[now]=bj[t];
son[now][1]=t;
}
}
up(now);
sz.add(bj[now],1);
}
inline int calc(int u)
{
splay(u);
int res=sz.ask(bj[u]);
return res-size[son[u][0]];
}
int main()
{
int i,j,p,q;
cin>>n>>m;
for(i=1;i<n;i++)
{
scanf("%d%d",&p,&q);
to[p].push_back(q);
to[q].push_back(p);
}
dfs(n,-1);
tt=n;
for(i=1;i<=m;i++)
{
scanf("%s",str);
if(str[0]=='u')
{
scanf("%d",&p);
acc(p,++tt),splay(p),fz[p]^=1;
}
else if(str[0]=='c')
{
scanf("%d%d",&p,&q);
printf("%d\n",calc(p)<calc(q)?p:q);
}
else
{
scanf("%d",&p);
printf("%d\n",calc(p));
}
}
}