HDU4008 Parent and son(树形DP LCA)

先记录以1为根时每个节点子树儿子节点的最大与次小值,询问x, y时,先判断x在不在y的子树范围内,若不在,结果为y的儿子结点,后继的最小值。

若x在y的子树范围内,若y儿子最小值是x的前驱,从次小值与父亲节点转移,否则从最小值与父亲节点转移。

 

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#include<utility>
using namespace std;
typedef long long LL;
const int N = 100008, INF = 0x3F3F3F3F;
#define MS(a, num) memset(a, num, sizeof(a))
#define PB(A) push_back(A)
#define FOR(i, n) for(int i = 0; i < n; i++)

int dfn[N][2];
int fa[N];
int son[N][2], des[N];
struct Node{
	int to,next;
}edge[N * 2];


int head[N],tot, deg[N];
int tim;
void init(){
	memset(head, -1, sizeof(head));
	memset(deg, 0, sizeof(deg));
	tot = 0;
}
void add(int u, int to){
	edge[tot].to=to;
	edge[tot].next=head[u];
	deg[u]++;
	head[u]=tot++;
}

void dfs(int u, int f){
	fa[u] = f;
	dfn[u][0] = tim++;

	son[u][0] = INF;
	son[u][1] = INF;
	des[u] = INF;
	for(int i = head[u]; ~i ; i = edge[i].next){
		int v = edge[i].to;
		if(v != f){
			dfs(v, u);
			son[u][1] = min(son[u][1], v);
			if(son[u][0] > son[u][1]){
				swap(son[u][0], son[u][1]);
			}
			des[u] = min(des[u], v);
			des[u] = min(des[u], des[v]);
		}
	}
	dfn[u][1] = tim++;
}

bool isFa(int x, int y){
	if(dfn[x][0] <= dfn[y][0]  && dfn[x][1] >= dfn[y][0]){
		return true;
	}
	return false;
}

int main(){
    int t;
    cin>>t;
    while(t--){
    	int n, q;
    	scanf("%d %d",  &n, &q);
    	init();
    	for(int i = 0; i < n - 1; i++){
            int u, v;
    		scanf("%d %d", &u, &v);
    		add(u, v);
    		add(v, u);
    	}
    	tim = 0;
    	dfs(1, INF);//1号节点父亲注意要为NF,便于处理

    	int des2 = INF;//1号节点子树后继次小值
    	int minv  = INF;//判断1号节点子树后继最小值从哪个儿子节点发出
    	for(int i = head[1]; ~i; i = edge[i].next){
    		int v = edge[i].to;
    		int tp = min(v, des[v]);
    		if(tp != des[1] && tp < des2){
    			des2 = tp;
    		}
    		if(tp == des[1]){
                minv = v;
    		}
    	}

    	while(q--){
    		int x, y;
    		scanf("%d %d", &x, &y);
    		if(deg[y] == 1){
    			printf("no answers!\n");
    			continue;
    		}
    		if(isFa(y, x)){//x在y子树范围内(以1为根时)
    			int mson, mdes;
    			if(isFa(son[y][0], x)){
                    mson = min(son[y][1], fa[y]);
                }else{
                    mson = min(son[y][0], fa[y]);
    			}

    			if(y != 1){
    				mdes = 1;
    			}else{
    			    //y不是节点1,要判断
    				if(isFa(minv, x)){
    					mdes = des2;
    				}else{
    					mdes = des[y];
    				}
    			}
    			printf("%d %d\n", mson, mdes);

    		}else{
    		    //x不在y子树范围内(以1为根时),直接输出
    			printf("%d %d\n", son[y][0], des[y]);
    		}
    	}
    	printf("\n");
    }

    return 0;
}

  

posted @ 2016-08-06 22:50  vwirtveurit  阅读(311)  评论(0编辑  收藏  举报