hdu 5927.Auxiliary Set

http://acm.hdu.edu.cn/showproblem.php?pid=5927

题意:给一个树,再给出一个查询(包含不重要点),除了查询给出的不重要点意外的都是重要点。求一个几个中有多少元素,这个集合包括:重要点,不重要点并且是两个不同重要点的共同祖先。

只需要先遍历一遍求出树的深度,父节点,孩子节点个数。

把输入的不重要节点根据深度从深到浅排序,检查每个不重要节点,如果他没有孩子就把他父亲的孩子数减一。如果他有两个以上的孩子,那说明他一定直接或者间接的是两个不同重要节点的祖先。

 1 #include<iostream>
 2 #include<list>
 3 #include<algorithm>
 4 #include<string.h>
 5 using namespace std;
 6 struct node
 7 {
 8     int depth,fa,ch,ch2;//记录层数;父节点是谁;孩子节点的个数;保存孩子节点的个数恢复用(每次查询会修改某些节点的孩子个数)
 9     list<int> side;//存边
10 };
11 node s[100002];//
12 bool v[100002];//访问标记
13 int s2[100002];//存每次查询的不重要节点
14 void dfs(int n,int de)//dfs求各节点深度,父节点,孩子个数
15 {
16     v[n]=1;
17     s[n].ch=s[n].side.size();//孩子个数等于有关系的点的数量减一(除了根节点)
18     if(n!=1)s[n].ch--;        //减一
19     s[n].ch2=s[n].ch;//保存孩子节点个数
20     s[n].depth=de;//深度
21     list<int>::iterator q = s[n].side.begin();
22     while(q!=s[n].side.end())
23     {
24         if(v[*q])//由于从根节点开始访问的,父节点肯定已经被访问到了,所以在有关的点中被访问过的就是父节点
25         {
26             s[n].fa = *q;
27         }
28         else
29         {
30             dfs(*q,de+1);
31         }
32         q++;
33     }
34 }
35 
36 bool cmp(const int &a,const int &b)//不重要点根据深度排序的比较函数
37 {
38         return s[a].depth>s[b].depth;
39 }
40 
41 int main()
42 {
43     int T,t=0;
44     scanf("%d",&T);
45     while(t++<T)
46     {
47         printf("Case #%d:\n", t);
48         int N,n,q,Q,a,b;
49         scanf("%d %d",&N,&Q);
50         n=0;
51         while(n++<N-1)
52         {
53             scanf("%d %d",&a,&b);
54             if(v[a])//多个样例的时候初始化用的
55             {
56                 v[a]=0;
57                 s[a].side.clear();
58             }
59             if(v[b])
60             {
61                 s[b].side.clear();
62                 v[b]=0;
63             }
64             s[a].side.insert(s[a].side.begin(),b);//两边都存一下
65             s[b].side.insert(s[b].side.begin(),a);
66         }
67         dfs(1,0);
68         q=0;
69         while(q++<Q)
70         {
71             int x,i=0;
72             scanf("%d",&x);
73             while(i<x)
74             {
75                 scanf("%d",&s2[i]);
76                 i++;
77             }
78             sort(s2,s2+i,cmp);//根据深度排序从最深的节点开始检查
79             int ans = N - i;
80             i=0;
81             while(i<x)
82             {
83                 if(s[s2[i]].ch==0)s[s[s2[i]].fa].ch--;//如果这个不重要节点没有孩子,他父节点的孩子数就减一(他自己不是重要节点,也无法提供是重要节点的子孙,这个子树就没有用了)
84                 if(s[s2[i]].ch>=2)ans++;//(如果这个不重要节点的孩子树≥2,那说明他一定是两个不同重要节点的最近祖先)
85                 i++;
86             }
87             printf("%d\n",ans);    
88             i=0;
89             while(i<x)//把所有不重要节点的父节点的孩子数复原
90             { 
91                 s[s[s2[i]].fa].ch=s[s[s2[i]].fa].ch2;
92                 i++;
93             }
94         }
95     }
96     return 0;
97 }

猜你喜欢

转载自www.cnblogs.com/icfir/p/9027194.html