题目链接:
F - Auxiliary Set
学习网址:https://blog.csdn.net/yiqzq/article/details/81952369
题目大意一棵节点数为n的有根数,根节点为1,一开始所有的点都是重点,接下来有q次询问,每次询问把m个点变为轻点,问你树中还有多少个重点。
重点应该满足的条件为:
1.它本身是重点。
2.它为两个重点的最近公共祖先。
每次询问之后在下次询问前,所有的点都恢复为重点。
具体思路:对于每个点保存他的深度。因为每次输入的数不重要的点,首先对于这些不重要的点按照深度从大到小进行排序, 然后先去处理深度大的。当处理深度大的时候,可以保证这个节点下面是没有不重要的点的,也就是这个节点的下面全都是重要的节点,那么这个点也肯定是符合的。然后往上更新的时候,如果当前的不重要节点下面没有点了,那么这个不重要节点的父亲往下的儿子数就应该减去1,也就是说这个分支下不存在重要的节点了。
AC代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 # define ll long long 4 const int maxn = 2e5+100; 5 int n,m; 6 vector<int>edge[maxn]; 7 void addedge(int fr,int to) 8 { 9 edge[fr].push_back(to); 10 } 11 int sto[maxn]; 12 int depth[maxn]; 13 int son1[maxn],son2[maxn]; 14 int father[maxn]; 15 void init() 16 { 17 for(int i=1; i<=n; i++) 18 { 19 edge[i].clear(); 20 son1[i]=0; 21 } 22 } 23 void dfs(int cur,int fa,int dep) 24 { 25 father[cur]=fa; 26 depth[cur]=dep+1; 27 for(int i=0; i<edge[cur].size(); i++) 28 { 29 int to=edge[cur][i]; 30 if(to==fa) 31 continue; 32 son1[cur]++; 33 dfs(to,cur,dep+1); 34 } 35 } 36 bool cmp(int t1,int t2) 37 { 38 return depth[t1]>depth[t2]; 39 } 40 int main() 41 { 42 int T; 43 int Case=0; 44 scanf("%d",&T); 45 while(T--) 46 { 47 int st,ed; 48 scanf("%d %d",&n,&m); 49 init(); 50 for(int i=1; i<n; i++) 51 { 52 scanf("%d %d",&st,&ed); 53 addedge(st,ed); 54 addedge(ed,st); 55 } 56 printf("Case #%d:\n",++Case); 57 dfs(1,0,0); 58 while(m--) 59 { 60 int sz,ans; 61 scanf("%d",&sz); 62 ans=n-sz; 63 for(int i=1; i<=sz; i++) 64 { 65 scanf("%d",&sto[i]); 66 son2[sto[i]]=son1[sto[i]]; 67 } 68 sort(sto+1,sto+sz+1,cmp); 69 for(int i=1; i<=sz; i++) 70 { 71 if(son2[sto[i]]>=2) 72 ans++; 73 if(son2[sto[i]]==0) 74 son2[father[sto[i]]]--; 75 } 76 printf("%d\n",ans); 77 } 78 } 79 return 0; 80 }