#LCT,树状数组#CF1137F Matches Are Not a Child's Play
分析
考虑从删除序列末尾来看,最大值一定在末尾,
然后与次大值之间夹了整条路径的点,降序以此类推
实际上从小到大是每个点到最大点的路径被打通的过程,由此分成若干条实链。
删除序列的位置实际上是到实链底端的距离加上其它实链底端小于该实链底端的实链总长度之和。
考虑维护每个点所处的实链底端的特征值(当变为最大值时,特征值发生改变),可以标记永久化
对于每一种实链用树状数组维护大小,每次修改新建特征值,换根即可。
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
using namespace std;
const int N=200011; struct node{int y,next;}e[N<<1];
int c[N<<1],as[N],et=1,rk[N],n,ext,m,Q;
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void update(int x,int y){
for (;x<=m;x+=-x&x) c[x]+=y;
}
int query(int x){
int ans=0;
for (;x;x-=-x&x) ans+=c[x];
return ans;
}
struct Splay{
int son[N][2],stac[N],TOP,fat[N],siz[N]; bool rev[N];
bool unroot(int x){return son[fat[x]][0]==x||son[fat[x]][1]==x;}
bool Is_R(int x){return son[fat[x]][1]==x;}
void pup(int x){siz[x]=siz[son[x][0]]+siz[son[x][1]]+1;}
void Rev(int x){swap(son[x][0],son[x][1]),rev[x]^=1;}
void pdown(int x){
if (son[x][0]) rk[son[x][0]]=rk[x];
if (son[x][1]) rk[son[x][1]]=rk[x];
if (rev[x]){
if (son[x][0]) Rev(son[x][0]);
if (son[x][1]) Rev(son[x][1]);
rev[x]=0;
}
}
void rotate(int x){
int Fa=fat[x],FFa=fat[Fa],wh=Is_R(x),t=son[x][wh^1];
if (unroot(Fa)) son[FFa][Is_R(Fa)]=x;
son[x][wh^1]=Fa,son[Fa][wh]=t;
if (t) fat[t]=Fa; fat[Fa]=x,fat[x]=FFa;
pup(Fa),pup(x);
}
void splay(int x){
int y=x; stac[TOP=1]=y;
while (unroot(y)) stac[++TOP]=y=fat[y];
for (;TOP;--TOP) pdown(stac[TOP]);
for (;unroot(x);rotate(x)){
int Fa=fat[x];
if (unroot(Fa)) rotate((Is_R(x)^Is_R(Fa))?x:Fa);
}
}
void Access(int x){
int y=0;
for (;x;x=fat[y=x]){
splay(x);
update(rk[x],siz[son[x][1]]-siz[x]);
son[x][1]=y,pup(x);
}
update(ext,siz[y]);
}
void Make_root(int x){Access(x),splay(x),Rev(x),rk[x]=ext;}
}Tre;
void dfs(int x){
rk[x]=x;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=Tre.fat[x]){
Tre.fat[e[i].y]=x,dfs(e[i].y);
if (rk[x]<rk[e[i].y])
rk[x]=rk[e[i].y],Tre.son[x][1]=e[i].y;
}
Tre.siz[x]=Tre.siz[Tre.son[x][1]]+1;
}
int main(){
ext=n=iut(),Q=iut(),m=n+Q;
for (int i=1;i<n;++i){
int x=iut(),y=iut();
e[++et]=(node){y,as[x]},as[x]=et;
e[++et]=(node){x,as[y]},as[y]=et;
}
dfs(n);
for (int i=1;i<=n;++i) ++c[rk[i]];
for (int i=n;i;--i)
if (rk[i]==i) update(i,c[i]),c[i]>>=1;
for (int i=1;i<=Q;++i){
char ch=getchar();
while (!isalpha(ch)) ch=getchar();
if (ch=='u') ++ext,Tre.Make_root(iut());
else if (ch=='w'){
int x=iut(); Tre.splay(x);
print(query(rk[x])-Tre.siz[Tre.son[x][0]]);
putchar(10);
}else{
int x=iut(),y=iut(),sx,sy;
Tre.splay(x),sx=Tre.siz[Tre.son[x][1]];
Tre.splay(y),sy=Tre.siz[Tre.son[y][1]];
if (rk[x]!=rk[y]) print(rk[x]<rk[y]?x:y);
else print(sx<sy?x:y);
putchar(10);
}
}
return 0;
}