链接
官方的数据很水,暴力可a,2332是加强版。
算法:并查集
思路:如果我们按询问顺着来弄,并查集将无法实现,因为一个点一旦指向了深度更小的点,就再也无法指回深度较大的点了。所以我们考虑倒序处理。
先将所有的操作离线,对所有修改操作进行实现,然后dfs求出每个点的祖先中最近的被标记点,可以在O(n)的时间内实现。
然后考虑倒着往回操作,每一次查询只需记录下来被查询点的最终父亲是谁。而每一次修改操作就是将w[x]--,一旦w[x]变为0了,意味着他不再被标记了。
那么我们就让他指向他相邻的那个父亲的最终父亲即可。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int inf=1e6+1; 4 int n,q,w[inf]; 5 int fa[inf],last[inf]; 6 int fi[inf],tot,to[inf<<1],next[inf<<1]; 7 void edge_add(int x,int y){ 8 to[++tot]=y; 9 next[tot]=fi[x]; 10 fi[x]=tot; 11 } 12 void dfs(int x,int f){ 13 fa[x]=f; 14 if(w[x])last[x]=x; 15 else last[x]=last[fa[x]]; 16 for(int i=fi[x];i;i=next[i]){ 17 if(to[i]==f)continue; 18 dfs(to[i],x); 19 } 20 } 21 struct Q{ 22 int x,ans; 23 char c; 24 void read(){ 25 char s[5]; 26 scanf("%s%d",s,&x); 27 c=s[0]; 28 } 29 }g[inf]; 30 void init(int x){ 31 g[x].read(); 32 if(g[x].c=='C'){ 33 w[g[x].x]++; 34 } 35 } 36 int get_last(int x){ 37 return w[x]?x:last[x]=get_last(last[x]); 38 } 39 int main() 40 { 41 freopen("tree++.in","r",stdin); 42 freopen("tree++.out","w",stdout); 43 scanf("%d%d",&n,&q); 44 for(int i=1;i<n;i++){ 45 int x,y; 46 scanf("%d%d",&x,&y); 47 edge_add(x,y);edge_add(y,x); 48 } 49 w[1]=1; 50 for(int i=1;i<=q;i++){ 51 init(i); 52 } 53 dfs(1,0); 54 for(int i=q;i>=1;i--){ 55 if(g[i].c=='C'){ 56 w[g[i].x]--; 57 if(!w[g[i].x])last[g[i].x]=get_last(fa[g[i].x]); 58 } 59 else { 60 g[i].ans=get_last(g[i].x); 61 } 62 } 63 for(int i=1;i<=q;i++){ 64 if(g[i].c=='Q'){ 65 printf("%d\n",g[i].ans); 66 } 67 } 68 return 0; 69 }