您的位置:首页 > 其它

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

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: