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;
}

  

时间: 2024-10-12 15:24:38

HDU4008 Parent and son(树形DP LCA)的相关文章

【bzoj3362/3363/3364/3365】[Usaco2004 Feb]树上问题杂烩 并查集/树形dp/LCA/树的点分治

题目描述 农夫约翰有N(2≤N≤40000)个农场,标号1到N,M(2≤M≤40000)条的不同的垂直或水平的道路连结着农场,道路的长度不超过1000.这些农场的分布就像下面的地图一样, 图中农场用F1..F7表示, 每个农场最多能在东西南北四个方向连结4个不同的农场.此外,农场只处在道路的两端.道路不会交叉且每对农场间有且仅有一条路径.邻居鲍伯要约翰来导航,但约翰丢了农场的地图,他只得从电脑的备份中修复了.每一条道路的信息如下: 从农场23往南经距离10到达农场17 从农场1往东经距离7到达农

(树形dp+LCA倍增法)CSU 1915 - John and his farm

题意: 有一个棵树,现在让你找两个点连接起来,这样必然成为一个环,现在要求这些环长度的期望,也就是平均值. 分析: 第一次做LCA题,做多校的时候,瞎几把找了模板敲,敲了个八九不离十,只是姿势不太好,需要考虑很多细节. 其实我觉得这题最多只能算中等题. 因为一直没空,写题解也晚了,已经有很多人写了题解,都写的不错.反正比我厉害. 这题用倍增法比较好一些,因为会用到关键点,也就是当v和u处在同一棵子树中时,找到更高点的下面那个点,倍增法通过深度跳跃可以很快找到.处理起来比其他两个LCA算法都方便.

HDU 4008 Parent and son

树形DP+LCA+思路.这题可真是有点难度......所以准备详细写一下题解. 题意:给一颗无根树,有Q次询问,每次询问指定一个根节点X,然后让你计算Y节点的儿子和子孙中,编号最小的节点是多少. 我们先以1为根节点进行一次树形DP,记录下每个节点的儿子和子孙中,编号最小的节点是多少. 首先很容易想到一种情况:就是X和Y的最近公共祖先不是Y,这个时候,结果和以1为根节点建树是一模一样的,因为把X提到最上面去,不会影响到Y的子树的情况. 剩余的情况就是X和Y的最近公共祖先等于Y(这种情况就是X在Y的

HDU 4008 Parent and son LCA+树形dp

题意: 给定case数 给定n个点的树,m个询问 下面n-1行给出树边 m个询问 x y 问:以x为根,y子树下 y的最小点标的儿子节点 和子孙节点 思路: 用son[u][0] 表示u的最小儿子 son[u][2] 表示u的次小儿子 son[u][1] 表示u的最小子孙 若lca(x,y)  !=y  则就是上述的答案 若lca(x,y) == y 1.y != 1 那么最小儿子就是除了x外的节点,且此时father[y] 也是y的儿子节点, 而最小的子孙节点就是1 2.y==1 那么特殊处理

HDOJ 5293 Tree chain problem LCA+树链剖分+树形DP

[题意] 给定一颗树上的几条链和每条链的权值,求能取出的不含有公共节点的链的最大权值.... [解] 预处理每条链的lca 树形DP, d[i]表示取到这个节点时可以得到的最大值 , sum[i]=sigma( d[k] | k 是i的子节点) 如果不取i  d[i]=sum[i] 如果取i , e是lca为i的链则 d[i]=max(d[i],e的权值+sigma(sum[k])-sigma(d[k]))  k为树链上的点 可以用树链剖分+树装数组在nlogn的时间复杂度内求链上的值 Tree

Codeforces 418d Big Problems for Organizers [树形dp][倍增lca]

题意: 给你一棵有n个节点的树,树的边权都是1. 有m次询问,每次询问输出树上所有节点离其较近结点距离的最大值. 思路: 1.首先是按照常规树形dp的思路维护一个子树节点中距离该点的最大值son_dis[i],维护非子树节点中距离该点的最大值fa_dis[i]; 2.对于每个节点维护它最大的三个儿子节点的son_dis; 3.维护up[i][j]和down[i][j]数组,这个类似倍增lca里边的fa[i][j],up[i][j]代表的含义是从第j个点向上到它的第2^i个父节点这条链上的点除了该

HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形dp, 对于每条链u,v,w,我们只在lca(u,v)的顶点上处理它 让dp[i]表示以i为根的指数的最大值,sum[i]表示dp[vi]的和(vi为i的儿子们) 则i点有两种决策,一种是不选以i为lca的链,则dp[i]=sum[i]. 另一种是选一条以i为lca的链,那么有转移方程:dp[i]=

【BZOJ2286】【SDOI2011】消耗战 LCA单调性(构建虚树)+树形DP

题解: 首先我们考虑每次都做一遍树形DP(树形DP自己脑补去,随便乱搞就过了). 显然这是TLE无疑的. 所以可以利用LCA单调性构建虚树. 思想: 我们发现每次树形DP有很多点用不到,但是却需要被扫过,让他们见鬼去吧! 实现: 我们只对每次扫的图插入本次询问需要的节点,以及它们的LCA. 这样询问了m个点,虚树就至多只需要2m个点(so quick). 而插入顺序上不妨利用LCA单调性来把点按dfs度排个序,然后挨个插入单调栈. 同时我们要保证单调栈维护的是一条链,也就是一旦不是链了,我们自然

poj3417 LCA + 树形dp

Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Description Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNet