zoukankan      html  css  js  c++  java
  • 祖孙询问

    祖孙询问


    Description

    已知一棵(n)个节点的有根树。有(m)个询问。每个询问给出了一对
    节点的编号(x)(y),询问(x)(y)的祖孙关系。


    Input Format

    输入第一行包括一个整数n表示节点个数。
    接下来n行每行一对整数对(a)(b)表示(a)(b)之间有连边。如果(b)(-1),那么(a)就是树的根。
    (n+2)行是一个整数(m)表示询问个数。
    接下来(m)行,每行两个正整数(x)(y)


    Output Format

    对于每一个询问,输出1:如果(x)(y)的祖先,输出2:如果(y)(x)的祖先,否则输出(0)


    Sample Input

    10
    234 -1
    12 234
    13 234
    14 234
    15 234
    16 234
    17 234
    18 234
    19 234
    233 19
    5
    234 233
    233 12
    233 13
    233 15
    233 19
    
    

    Sample Output

    1
    0
    0
    0
    2
    

    Hint

    对于(30%)的数据,(n,m≤1000)
    对于(100%)的.据,(n,m≤40000),每个节点的编号都不超过(40000)

    Solution

    首先这题应该是一个(LCA)模板题,但是我们这里考虑用(dfs)来做。

    其实这题的主要思想应该是一个时间戳的应用。

    我们记录当前搜索到这个点的时间(变灰时间)和递归到这个点的时间(变黑时间)

    然后我们将变灰时间和变黑时间进行比较就可以找出两个点的关系

    #include<bits/stdc++.h>
    #define Re register int
    using namespace std;
    int N,M,a,b,Num,head[80005],Start,Dep[40005],Ret[40005],Time;
    bool Check[40005];
    struct Edge{
    	int To,Next;
    }edge[80005];//双向建边数组记得开两倍
    inline void Add_Edge(int u,int v){
    	edge[++Num].Next=head[u];
    	edge[Num].To=v;
    	head[u]=Num;
    }
    inline void Dfs(int Now){
    	Dep[Now]=++Time; Check[Now]=true; //变灰的时间 
    	for (Re i=head[Now];i;i=edge[i].Next) if (!Check[edge[i].To]) Dfs(edge[i].To);
    	Ret[Now]=++Time; //变黑的时间 
    }
    int main(){
    	scanf("%d",&N);
    	for (Re i=1; i<=N; ++i){
    		scanf("%d%d",&a,&b);
    		if (b==-1) Start=a;
    		else {
    			Add_Edge(a,b);Add_Edge(b,a);
    		}
    	}
    	Dfs(Start);
    	scanf("%d",&M);
    	for (Re i=1; i<=M; ++i){
    		scanf("%d%d",&a,&b);
    		if (Dep[a]<Dep[b]&&Ret[a]>Ret[b]) printf("1
    ");
    		else if (Dep[a]>Dep[b]&&Ret[a]<Ret[b]) printf("2
    ");
    		else printf("0
    ");
    	}
    	return 0;
    }
    
    

    第二种方法......
    就是正版一点的(LCA)

    (LCA)模板在上面随笔的转发

    (LCA)判断两个点的高低,然后让低的那个点往上跳,一直跳到两个点在同一层,记住这里指的是同一层;
    然后在判断这两个点是否重合,如果重合就可以输出答案
    答案是(1)还是(2)那么就是看两个点的高低......

    #include<bits/stdc++.h>
    #define Re register int
    using namespace std;
    int N,M,a,b,Num,head[80005],Root;
    int f[40005][21],d[40005];
    bool Check[3];
    struct Edge{
    	int To,Next;
    }edge[80005];
    inline void Add_Edge(int u,int v){
    	edge[++Num].Next=head[u];
    	edge[Num].To=v;
    	head[u]=Num;
    }
    inline void dfs(int Now,int fa){
    	d[Now]=d[fa]+1; f[Now][0]=fa;
    	for (Re i=1; (1<<i)<=d[Now]; ++i) f[Now][i]=f[f[Now][i-1]][i-1];
    	for (Re i=head[Now];i;i=edge[i].Next) if (edge[i].To^fa) dfs(edge[i].To,Now);
    }
    inline void LCA(int a,int b){
    	if (d[a]>d[b]) swap(a,b),Check[0]=true;
    	for (Re i=20; i>=0; --i) if (d[a]<=d[f[b][i]]) b=f[b][i];
    	if (a==b) Check[1]=true;
    }
    int main(){
    	scanf("%d",&N);
    	for (Re i=1; i<=N; ++i){
    		scanf("%d%d",&a,&b);
    		if (b==-1) Root=a;
    		Add_Edge(a,b);
    		Add_Edge(b,a);
    	}
    	dfs(Root,0);
    	scanf("%d",&M);
    	for (Re i=1; i<=M; ++i){
    		memset(Check,false,sizeof(Check));
    		scanf("%d%d",&a,&b);
    		LCA(a,b);
    		if (Check[0]&&Check[1]) printf("2
    ");
    		else if (!Check[0]&&Check[1]) printf("1
    ");
    		else printf("0
    ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    广播与服务知识点总结
    Intent和Activity知识点总结
    数据库基础
    Java 中JOptionPane的基本使用方法
    Eclipse 自动补全功能失效解决办法及修改快捷键方法
    hdu 2095 find your present (2)
    sort()
    qsort()
    算法学习——分治算法
    NYOJ——街区最短路径问题
  • 原文地址:https://www.cnblogs.com/to-the-end/p/11349941.html
Copyright © 2011-2022 走看看