• 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!
    ");
        			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
    ", mson, mdes);
    
        		}else{
        		    //x不在y子树范围内(以1为根时),直接输出
        			printf("%d %d
    ", son[y][0], des[y]);
        		}
        	}
        	printf("
    ");
        }
    
        return 0;
    }
    

      

  • 相关阅读:
    合并二叉树
    剑指 Offer 68
    剑指 Offer 42. 连续子数组的最大和
    C语言 递归实现迷宫寻路问题
    C语言数据结构 统计英文文字每个“单词”出现次数
    C语言 双链表的频度排序管理
    C语言 插入排序使链表递增
    c语言 简单的天数计算器
    数据结构 链表的头插法逆置
    C语言 删除指定的单词
  • 原文地址:https://www.cnblogs.com/IMGavin/p/5745080.html
Copyright © 2020-2023  润新知