树剖显然可以做。
然而有一种更神奇的方法,并查集+时光倒流。
每个节点指向它上面最近的标记节点,标记节点指向自己,然后删除标记,就可以用并查集查询了。
#include <map> #include <cmath> #include <queue> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=k;--i) #define ll long long #define mp make_pair #define maxn 200005 int opt[maxn],x[maxn],n,q,a,b,cnt[maxn]; int h[maxn],to[maxn],ne[maxn],en=0,f[maxn]; int fa[maxn],ans[maxn]; void add(int a,int b) {to[en]=b;ne[en]=h[a];h[a]=en++;} void dfs(int o,int fa) { f[o]=fa; for (int i=h[o];i>=0;i=ne[i]) if (to[i]!=fa) dfs(to[i],o); } int find(int x) { if (fa[x]==x) return x; else return fa[x]=find(fa[x]); } int main() { memset(h,-1,sizeof h); scanf("%d%d",&n,&q); F(i,2,n) { int a,b; scanf("%d%d",&a,&b); add(a,b); add(b,a); } dfs(1,0); cnt[1]++; F(i,1,q) { char s[10]; scanf("%s%d",s,&x[i]); switch(s[0]) { case 'C':opt[i]=1;cnt[x[i]]++;break; case 'Q':opt[i]=2;break; } } F(i,1,n) if (cnt[i]) fa[i]=i; else fa[i]=f[i]; D(i,q,1) { if (opt[i]==1) { cnt[x[i]]--; if (!cnt[x[i]]) fa[x[i]]=f[x[i]]; } else ans[i]=find(x[i]); } F(i,1,q) if (opt[i]==2) printf("%d ",ans[i]); }