zoukankan      html  css  js  c++  java
  • 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 那么特殊处理一下。用map维护一下除了u节点下的子树。1的最小子孙节点


    #include <stdio.h>
    #include <iostream>
    #include <algorithm>
    #include <sstream>
    #include <stdlib.h>
    #include <string.h>
    #include <limits.h>
    #include <string>
    #include <time.h>
    #include <math.h>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    using namespace std;
    #define inf 1000000
    #define N 100050
    struct Edge{
        int from, to, dis, nex;
    }edge[5*N];
    int head[N],edgenum,dis[N],fa[N][20],dep[N];  //fa[i][x] 是i的第2^x个父亲(假设超过范围就是根)
    void add(int u,int v,int w){
        Edge E={u,v,w,head[u]};
        edge[edgenum] = E;
        head[u]=edgenum++;
    }
    void bfs(int root){
        queue<int> q;
        fa[root][0]=root;dep[root]=0;dis[root]=0;
        q.push(root);
        while(!q.empty()){
            int u=q.front();q.pop();
            for(int i=1;i<20;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
            for(int i=head[u]; ~i;i=edge[i].nex){
                int v=edge[i].to;if(v==fa[u][0])continue;
                dep[v]=dep[u]+1;dis[v]=dis[u]+edge[i].dis;fa[v][0]=u;
                q.push(v);
            }
        }
    }
    int move(int x,int y){//把x移动到y以下
        int D = dep[x] - dep[y]-1;
        while(D){
            int z = (int)(log10(1.0*D)/log10(2.0));
            x = fa[x][z];
            D-=1<<z;
        }
        return x;
    }
    int Lca(int x,int y){
        if(dep[x]<dep[y])swap(x,y);
        for(int i=0;i<20;i++)if((dep[x]-dep[y])&(1<<i))x=fa[x][i];
        if(x==y)return x;
        for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    void init(){memset(head, -1, sizeof head); edgenum = 0;}
    int son[N][3], Fa[N];
    //0是最小 1是子孙最小 2是次小
    void dfs(int u,int  father){
    	Fa[u] = father;
        son[u][0] = son[u][1] = son[u][2] = inf;
        for(int i = head[u]; ~i; i = edge[i].nex){
            int v = edge[i].to; if(v==father)continue;
            dfs(v,u);
            if(v<son[u][0])
    			son[u][2] = son[u][0], son[u][0] = v;
    		else son[u][2] = min(son[u][2], v);
            son[u][1] = min(son[u][1], son[v][1]);
        }
        son[u][1] = min(son[u][1], son[u][0]);
    }
    map<int,int>mp;
    bool work(int x,int y){
        int lca = Lca(x,y), son1, son2;
            if(lca==y) {
    	        x = move(x,y);
    	        son1 = son[y][0];
    	        if(son1 == x) son1 = son[y][2];
    	        son1 = min(son1, Fa[y]);
    	        if(y==1) {
    	        	son2 = mp[x];
    			}
    			else son2 = 1;
      	    } else {
      	    	son1 = son[y][0];
      	    	son2 = son[y][1];
    		}
    	if(son1==inf||son2==inf)return false;
        printf("%d %d
    ",son1,son2);
        return true;
    }
    int n;
    int main(){
        int i,j,u,v,T,que;scanf("%d",&T);
        while(T--){
            init();
            scanf("%d %d",&n,&que);
            for(i = 1; i < n; i++) {
                scanf("%d %d",&u,&v);
                add(u,v,1);
                add(v,u,1);
            }
            bfs(1);
            dfs(1,1);
            Fa[1] = inf;
            mp.clear();
            int fir = inf, sec = inf;
            for(i = head[1]; ~i; i = edge[i].nex){
    			v = edge[i].to;
    			mp[v] = inf;
    			if(v<fir)sec = fir, fir = v;
    			else sec = min(sec, v);
    		}
    		
    		for(i = head[1]; ~i; i = edge[i].nex){
    			v = edge[i].to;
    			if(v!=fir)mp[v] = fir;
    			else mp[v] = sec;
    		}
    		fir = inf; sec = inf;
    	    for(i = head[1]; ~i; i = edge[i].nex){
    			v = edge[i].to;
    			if(son[v][1]<fir)sec = fir, fir = son[v][1];
    			else sec = min(sec, son[v][1]);
    		}
    	    for(i = head[1]; ~i; i = edge[i].nex){
    			v = edge[i].to;
    			if(son[v][1]!=fir)
    				mp[v] = min(mp[v], fir);
    			else
    				mp[v] = min(mp[v], sec);
      		}
            while(que--){
                scanf("%d %d",&u,&v);
                if(work(u,v)==false)
                    puts("no answers!");
            }
            puts("");
        }
        return 0;
    }
    


  • 相关阅读:
    找出占用磁盘空间最大的前10个文件或文件夹
    把inline函数的定义放在头文件中
    判断是大端字节序还是小端字节序
    在source insight 中添加系统字体
    C++ inline 函数
    标准I/O函数库的三类缓冲
    内存分配失败错误处理
    P1765 手机
    P1321 单词覆盖还原
    P1308 [NOIP2011 普及组] 统计单词数
  • 原文地址:https://www.cnblogs.com/mfmdaoyou/p/6740528.html
Copyright © 2011-2022 走看看