bzoj 4551[Tjoi2016&Heoi2016]树

  这题可以用并查集做,一开始统计一下记录每个点被标记了几次,除了被标记过的点外,其他节点都与其父亲所在集合合并,然后倒着做,做的时候如果有节点标记次数变为了0,则将其与其父亲合并。

  代码

 1 #include<cstdio>
 2 #include<queue>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define N 500100
 6 using namespace std;
 7 typedef long long ll;
 8 int n,m,i,a,b,dp,p[N],pre[N],tt[N];
 9 int F[N],v[N],sum[N],f[N],ans[N],tot;
10 char typ[N];
11 void link(int x,int y)
12 {
13     dp++;pre[dp]=p[x];p[x]=dp;tt[dp]=y;
14 }
15 void dfs(int x,int fa)
16 {
17     int i=p[x];
18     F[x]=fa;
19     while (i)
20     {
21         if (tt[i]!=fa)
22             dfs(tt[i],x);
23         i=pre[i];
24     }
25 }
26 int gf(int x)
27 {
28     int p=x,t;
29     while (p!=f[p]) p=f[p];
30     while (x!=p)
31     {
32         t=f[x];f[x]=p;x=t;
33     }
34     return p;
35 }
36 int main()
37 {
38     scanf("%d%d",&n,&m);
39     for (i=1;i<n;i++)
40     {
41         scanf("%d%d",&a,&b); 
42         link(a,b);link(b,a);
43     }
44     dfs(1,0);
45     sum[1]=1;
46     for (i=1;i<=m;i++)
47     {
48         scanf(" %c%d",&typ[i],&v[i]);
49         if (typ[i]=='C')
50         sum[v[i]]++;
51     }
52     for (i=1;i<=n;i++) f[i]=i;
53     for (i=1;i<=n;i++) if (!sum[i]) f[gf(i)]=gf(F[i]);
54     for (i=m;i>=1;i--)
55     {
56         if (typ[i]=='Q')
57         {
58             tot++;ans[tot]=gf(v[i]);
59         }
60         else
61         {
62             sum[v[i]]--;
63             if (sum[v[i]]==0) f[gf(v[i])]=gf(F[v[i]]);
64         }
65     }
66     for (i=tot;i>=1;i--)
67     printf("%d
",ans[i]);
68     
69 }
原文地址:https://www.cnblogs.com/fzmh/p/5444958.html