HDU 4008【树型DP+树儿子兄弟判断】

题目:Parent and son

题意:

输入N,Q,接着输入N-1条边,组成树,结点以1-N命名。

然后输入Q个提问,每个提问输入X,Y(X!=Y),表示当以X为树的根结点时,求Y的最小儿子和最小子孙。

解题思路:

以1为根,进行DFS遍历,DP每个结点的最小儿子和最小子孙,注意最小儿子要包括其father,方便后面处理。

有了这些信息后,对每个提问X,Y。分三种情况:

s

第一种情况:当Y==1时,X肯定是Y的儿子。这个要特殊处理,因为上面获得信息不能取得其最优解。因为DFS结果的最小子孙sx有可能跟x在同一棵子树上,那么当以X为树根时,Y的最小子孙肯定不是sx。所以结点1要预先处理。找出其最小的子孙sx1,并记录其的次根son1,也即是根的儿子,同理找出次小子孙sx2,son2。这样对每提问X,Y,若Y==1,则判断x是否为son1或为son1的子孙,若是,则Y的最小子孙为sx2,否则为sx1。

第二种情况:当X为Y的子孙时,很容易得Y的最小子孙是1,这就为什么预处理时以1为根进行DFS的原因^_^。最小儿子也不难判定。

第三种情况:这种情况与以1为根的情况相同。最小子孙即DFS求得的最小子孙,儿子是除father外的子孙,所以要记录最小与次小儿子。当最小儿子是其father时,则其最小儿子是次小儿子。

还有一个问题是如何判断x是Y的儿子呢?有很多种方法,这里用了DFS的性质,记录每个结点的进入栈时间和退出栈时间,当x的时间段在y的时间段内则表明x是y的儿子。这题只需判断儿子,足够了。

View Code
  1 #include <iostream>
2 #include <cstdio>
3 #include <string>
4 #include <cstring>
5 #include <algorithm>
6 #include <vector>
7 #include <map>
8
9 using namespace std;
10 const int MAX = 100000 + 10;
11 const int INF = 0x7fffffff;
12
13 struct TTree
14 {
15 int node;
16 int next;
17 }Tree[MAX * 10];
18 int N, Q, End;
19 int Next[MAX];
20 int B[MAX], E[MAX];
21 int MinDescendant[MAX], MinSon1[MAX], MinSon2[MAX];
22 int Time;
23
24 void init(int n)
25 {
26 for(int i = 1; i <= n; ++i)
27 {
28 Tree[i].next = 0;
29 Next[i] = i;
30 MinSon2[i] = MinSon1[i] = MinDescendant[i] = INF;
31 }
32 End = n;
33 Time = 0;
34 }
35 int getMin(int a, int b)
36 {
37 return a < b ? a : b;
38 }
39 void addEdge(int from, int to)
40 {
41 ++End;
42 Tree[Next[from]].next = End;
43 Tree[Next[from] = End].node = to;
44 Tree[End].next = 0;
45 }
46
47 void dfs(int father, int node)
48 {
49 B[node] = Time++;
50 MinSon1[node] = father;
51 for(int ix = Tree[node].next; ix != 0; ix = Tree[ix].next)
52 {
53 if(Tree[ix].node == father)
54 continue;
55 dfs(node, Tree[ix].node);
56 MinDescendant[node] = getMin(MinDescendant[node], MinDescendant[Tree[ix].node]);
57 MinDescendant[node] = getMin(MinDescendant[node], Tree[ix].node);
58 if(Tree[ix].node < MinSon1[node])
59 {
60 MinSon2[node] = MinSon1[node];
61 MinSon1[node] = Tree[ix].node;
62 }
63 else if(Tree[ix].node < MinSon2[node])
64 MinSon2[node] = Tree[ix].node;
65 }
66 E[node] = Time++;
67 }
68
69 bool isDescendant(int x, int y)
70 {
71 return B[x] > B[y] && E[x] < E[y];
72 }
73
74 int main()
75 {
76 freopen("in.txt","r",stdin);
77 int T;
78 int x, y;
79 scanf("%d", &T);
80 while(T--)
81 {
82 scanf("%d%d", &N, &Q);
83 init(N);
84 for(int i = 1; i <= N - 1; ++i)
85 {
86 scanf("%d%d", &x, &y);
87 addEdge(x, y);
88 addEdge(y, x);
89 }
90 dfs(INF, 1);
91 int min1 = INF, min2 = INF, son1 = INF, son2 = INF;
92 for(int ix = Tree[1].next; ix != 0; ix = Tree[ix].next)
93 {
94 int min = getMin(Tree[ix].node, MinDescendant[Tree[ix].node]);
95 if(min < min1)
96 {
97 min2 = min1;
98 min1 = min;
99 son2 = son1;
100 son1 = Tree[ix].node;
101 }
102 else if(min < min2)
103 {
104 min2 = min;
105 son2 = Tree[ix].node;
106 }
107 }
108 int minSon = INF, minDescendant = INF;
109 for(int i = 1; i <= Q; ++i)
110 {
111 scanf("%d%d", &x, &y);
112 if(y == 1)
113 {
114 if(MinSon1[1] != x && !isDescendant(x, MinSon1[1]))
115 minSon = MinSon1[1];
116 else
117 minSon = MinSon2[1];
118 if(son1 != INF && son1 != x && !isDescendant(x, son1))
119 minDescendant = min1;
120 else
121 minDescendant = min2;
122 }
123 else if(isDescendant(x, y))
124 {
125 if((MinSon1[y] != x && !isDescendant(x, MinSon1[y])) || isDescendant(y, MinSon1[y]))
126 minSon = MinSon1[y];
127 else
128 minSon = MinSon2[y];
129 minDescendant = 1;
130 }
131 else
132 {
133 if(MinSon1[y] != x && !isDescendant(y, MinSon1[y]))
134 minSon = MinSon1[y];
135 else
136 minSon = MinSon2[y];
137 minDescendant = MinDescendant[y];
138 }
139 if(minSon != INF && minDescendant != INF)
140 printf("%d %d\n", minSon, minDescendant);
141 else
142 printf("no answers!\n");
143 }
144 printf("\n");
145 }
146 return 0;
147 }

posted on 2011-09-15 16:53  Kenfly  阅读(761)  评论(4编辑  收藏  举报