题解:动态树,维护Splay最深的被标记过的点
每个询问先Access(x);
当然用树链剖分也可以
#include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int maxn=100009; const int oo=1000000000; int n,T; int fa[maxn],ch[maxn][2],dest[maxn],v[maxn]; inline int son(int x){ if(ch[fa[x]][1]==x)return 1; else return 0; } inline void pushup(int x){ dest[x]=dest[ch[x][1]]; if(!dest[x]){ if(v[x])dest[x]=x; } if(!dest[x])dest[x]=dest[ch[x][0]]; } inline bool isroot(int x){ return (ch[fa[x]][0]!=x)&&(ch[fa[x]][1]!=x); } inline void Rotate(int x){ int y=fa[x]; int z=fa[y]; int b=son(x),c=son(y); int a=ch[x][b^1]; if(!isroot(y))ch[z][c]=x; fa[x]=z; if(a)fa[a]=y; ch[y][b]=a; fa[y]=x;ch[x][b^1]=y; pushup(y);pushup(x); } void Splay(int x){ while(!isroot(x)){ int y=fa[x]; if(isroot(y)){ Rotate(x); }else{ if(son(x)==son(y)){ Rotate(y);Rotate(x); }else{ Rotate(x);Rotate(x); } } } } void Access(int x){ for(int t=0;x;t=x,x=fa[x]){ Splay(x);ch[x][1]=t;pushup(x); } } int cntedge; int head[maxn]; int to[maxn<<1],nex[maxn<<1]; void Addedge(int x,int y){ nex[++cntedge]=head[x]; to[cntedge]=y; head[x]=cntedge; } queue<int>q; int father[maxn]; void Bfs(){ q.push(1); while(!q.empty()){ int x=q.front();q.pop(); for(int i=head[x];i;i=nex[i]){ if(to[i]==father[x])continue; father[to[i]]=x; fa[to[i]]=x; q.push(to[i]); } } } int main(){ scanf("%d%d",&n,&T); for(int i=1;i<=n-1;++i){ int x,y; scanf("%d%d",&x,&y); Addedge(x,y); Addedge(y,x); } v[1]=1;dest[1]=1; Bfs(); while(T--){ char opty[10]; scanf("%s",opty); int x; scanf("%d",&x); if(opty[0]==‘C‘){ Splay(x);v[x]=1;pushup(x); }else{ Access(x);Splay(x);printf("%d\n",dest[x]); } } return 0; }