传送门
题解:
考虑树上最大值和次大值,显然链接它们的链最后删除,且一定是从次大值向最大值一个一个删除。
显然我们可以把树拆成若干条链,每条链上的点的删除顺序从一个端点依次向另一个端点。
注意到拆成链之后每条链内部的点是一起删除的,而链与链之间的删除顺序由链上最大值来决定。
定最大值所在节点为根,容易发现修改就是make_root,询问的话需要知道最大值小于该链最大值的链的siz总和,以及这条链上比该点先删除的点的数量,也就是处于同一条链且深度比它大的点的数量。
LCT+BIT搞定。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const
namespace IO{
inline char gc(){
static cs int Rlen=1<<22|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int get_s(char *s){
int len=0;char c;
while(isspace(c=gc()));
while(s[len++]=c,!isspace(c=gc())&&c!=EOF);
s[len]='\0';return len;
}
template<typename T>
inline T get(){
char c;T num;
while(!isdigit(c=gc()));num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
inline int gi(){return get<int>();}
}
using namespace IO;
using std::cerr;
using std::cout;
cs int N=2e5+7,M=N<<1|1;
int n,m;
int tr[M];
inline int add(int p,int v){for(;p<M;p+=p&-p)tr[p]+=v;}
inline int qy(int p){int r=0;for(;p;p^=p&-p)r+=tr[p];return r;}
std::vector<int> G[N];
int mx[N],siz[N];
int fa[N],son[N][2],rev[N];
inline void pushup(int u){siz[u]=siz[son[u][0]]+siz[son[u][1]]+1;}
inline void pushdown(int u){
if(rev[u]){
std::swap(son[u][0],son[u][1]);
rev[son[u][0]]^=1;
rev[son[u][1]]^=1;
rev[u]=0;
}
if(son[u][0])mx[son[u][0]]=mx[u];
if(son[u][1])mx[son[u][1]]=mx[u];
}
inline bool isrt(int u){return son[fa[u]][0]!=u&&son[fa[u]][1]!=u;}
inline bool which(int u){return son[fa[u]][1]==u;}
inline void Rotate(int u){
int p=fa[u],pp=fa[p],d=which(u);
if(!isrt(p))son[pp][which(p)]=u;
fa[u]=pp,fa[p]=u,fa[son[u][!d]]=p;
son[p][d]=son[u][!d],son[u][!d]=p;
pushup(p);pushup(u);
}
inline void Splay(int u){
static int q[N],qn;q[qn=1]=u;
for(int re p=u;!isrt(p);p=fa[p])q[++qn]=fa[p];
while(qn)pushdown(q[qn--]);
for(int re p=fa[u];!isrt(u);Rotate(u),p=fa[u])
if(!isrt(p))Rotate(which(p)==which(u)?p:u);
}
int now;
inline void access(int u){
for(int re ch=0;u;u=fa[ch=u]){
Splay(u);son[u][1]=0;pushup(u);
add(mx[u],-siz[u]);
add(now,siz[u]);
son[u][1]=ch,pushup(u);
}
}
inline void makert(int u){
++now;access(u);Splay(u);rev[u]^=1;mx[u]=now;
}
char s[10];
inline int query(int u){
Splay(u);return qy(mx[u])-siz[son[u][0]];
}
void dfs(int u,int p){
fa[u]=p;mx[u]=u;
for(int re v:G[u])if(v!=p){
dfs(v,u);
if(mx[v]>mx[u]){
mx[u]=mx[v],son[u][1]=v;
}
}
add(mx[u],1);
}
signed main(){
#ifdef zxyoi
freopen("fuck_it.in","r",stdin);
#endif
now=n=gi(),m=gi();
for(int re i=1;i<n;++i){
int u=gi(),v=gi();
G[u].push_back(v);
G[v].push_back(u);
}dfs(n,0);
while(m--){
switch(get_s(s)){
case 2:makert(gi());break;
case 4:cout<<query(gi())<<"\n";break;
case 7:{
int u=gi(),v=gi();
cout<<(query(u)<query(v)?u:v)<<"\n";
break;
}
}
}
return 0;
}