HDU 4008【树型DP+树儿子兄弟判断】
2011-09-15 16:53
197 查看
题目: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
题意:
输入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
#include <iostream> #include <cstdio> #include <string> #include <cstring> #include <algorithm> #include <vector> #include <map> using namespace std; const int MAX = 100000 + 10; const int INF = 0x7fffffff; struct TTree { int node; int next; }Tree[MAX * 10]; int N, Q, End; int Next[MAX]; int B[MAX], E[MAX]; int MinDescendant[MAX], MinSon1[MAX], MinSon2[MAX]; int Time; void init(int n) { for(int i = 1; i <= n; ++i) { Tree[i].next = 0; Next[i] = i; MinSon2[i] = MinSon1[i] = MinDescendant[i] = INF; } End = n; Time = 0; } int getMin(int a, int b) { return a < b ? a : b; } void addEdge(int from, int to) { ++End; Tree[Next[from]].next = End; Tree[Next[from] = End].node = to; Tree[End].next = 0; } void dfs(int father, int node) { B[node] = Time++; MinSon1[node] = father; for(int ix = Tree[node].next; ix != 0; ix = Tree[ix].next) { if(Tree[ix].node == father) continue; dfs(node, Tree[ix].node); MinDescendant[node] = getMin(MinDescendant[node], MinDescendant[Tree[ix].node]); MinDescendant[node] = getMin(MinDescendant[node], Tree[ix].node); if(Tree[ix].node < MinSon1[node]) { MinSon2[node] = MinSon1[node]; MinSon1[node] = Tree[ix].node; } else if(Tree[ix].node < MinSon2[node]) MinSon2[node] = Tree[ix].node; } E[node] = Time++; } bool isDescendant(int x, int y) { return B[x] > B[y] && E[x] < E[y]; } int main() { freopen("in.txt","r",stdin); int T; int x, y; scanf("%d", &T); while(T--) { scanf("%d%d", &N, &Q); init(N); for(int i = 1; i <= N - 1; ++i) { scanf("%d%d", &x, &y); addEdge(x, y); addEdge(y, x); } dfs(INF, 1); int min1 = INF, min2 = INF, son1 = INF, son2 = INF; for(int ix = Tree[1].next; ix != 0; ix = Tree[ix].next) { int min = getMin(Tree[ix].node, MinDescendant[Tree[ix].node]); if(min < min1) { min2 = min1; min1 = min; son2 = son1; son1 = Tree[ix].node; } else if(min < min2) { min2 = min; son2 = Tree[ix].node; } } int minSon = INF, minDescendant = INF; for(int i = 1; i <= Q; ++i) { scanf("%d%d", &x, &y); if(y == 1) { if(MinSon1[1] != x && !isDescendant(x, MinSon1[1])) minSon = MinSon1[1]; else minSon = MinSon2[1]; if(son1 != INF && son1 != x && !isDescendant(x, son1)) minDescendant = min1; else minDescendant = min2; } else if(isDescendant(x, y)) { if((MinSon1[y] != x && !isDescendant(x, MinSon1[y])) || isDescendant(y, MinSon1[y])) minSon = MinSon1[y]; else minSon = MinSon2[y]; minDescendant = 1; } else { if(MinSon1[y] != x && !isDescendant(y, MinSon1[y])) minSon = MinSon1[y]; else minSon = MinSon2[y]; minDescendant = MinDescendant[y]; } if(minSon != INF && minDescendant != INF) printf("%d %d\n", minSon, minDescendant); else printf("no answers!\n"); } printf("\n"); } return 0; }
相关文章推荐
- Hdu 4008 Parent and son(给你一棵树(n<=1e5),有Q次查询,每次输入X Y,意思是以X为根,输出Y的儿子节点中节点标号最小和子树中标号最小)
- hdu 4008 Parent and son 在树上查询以X为根的Y的儿子和子树节点中的最小节点 标记时间戳
- HDU 2444 The Accomodation of Students 判断二分图 + 最大匹配
- HDU 1272 HDU 1308&&POJ 1308(树的判断)(并查集)
- HDU 3864 D_num Miller Rabin 质数判断+Pollard Rho大整数分解
- HDU 4414 Finding crosses(暴力判断)
- hdu 1086 判断两个线段是否相交
- hdu 1042 N! java大数及判断文件末尾
- HDU 2108 逆时针给出多边形的顶点,判断是否为凸多边形,水题
- HDU 4370 0 or 1(最短路+最小环判断)
- hdu 1272 判断所给的图是不是生成树 (并查集)
- HDU 4474 Yet Another Multiple Problem【BFS+一个判断技巧】
- HDU 1878(1Y) (判断欧拉回路是否存在 奇点个数为0 + 一个联通分量 *【模板】)
- HDU 3478 Catch(判断奇数环)
- HDU 1086 You can Solve a Geometry Problem too(判断线段相交)
- hdu 1086(判断两线段是否相交)
- (hdu step 2.1.2)How many prime numbers(判断一个数是否是质数)
- 【01染色法判断二分匹配+匈牙利算法求最大匹配】HDU The Accomodation of Students
- trie树 和 树的存储--左儿子右兄弟 --- uva 11732
- (hdu step 9.1.1)A == B ?(在这个数字有可能是大数并且存在无效0的情况下,判断这两个数字是否相等)