cogs2274[HEOI 2016] tree【解题报告】

链接

 

官方的数据很水,暴力可a,2332是加强版。

算法:并查集

思路:如果我们按询问顺着来弄,并查集将无法实现,因为一个点一旦指向了深度更小的点,就再也无法指回深度较大的点了。所以我们考虑倒序处理。

先将所有的操作离线,对所有修改操作进行实现,然后dfs求出每个点的祖先中最近的被标记点,可以在O(n)的时间内实现。

然后考虑倒着往回操作,每一次查询只需记录下来被查询点的最终父亲是谁。而每一次修改操作就是将w[x]--,一旦w[x]变为0了,意味着他不再被标记了。

那么我们就让他指向他相邻的那个父亲的最终父亲即可。

 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 }
代码君

 

转载于:https://www.cnblogs.com/hyghb/p/7860602.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值