zoukankan      html  css  js  c++  java
  • 【模板】tarjanLCA [2017年6月计划 学习tarjanLCA]

    P3379 【模板】最近公共祖先(LCA)

    题目描述

    如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先。

    输入输出格式

    输入格式:

    第一行包含三个正整数N、M、S,分别表示树的结点个数、询问的个数和树根结点的序号。

    接下来N-1行每行包含两个正整数x、y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树)。

    接下来M行每行包含两个正整数a、b,表示询问a结点和b结点的最近公共祖先。

    输出格式:

    输出包含M行,每行包含一个正整数,依次为每一个询问的结果。

    输入输出样例

    输入样例#1:
    5 5 4
    3 1
    2 4
    5 1
    1 4
    2 4
    3 2
    3 5
    1 2
    4 5
    输出样例#1:
    4
    4
    1
    4
    4
    

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=10000,M<=10000

    对于100%的数据:N<=500000,M<=500000

    样例说明:

    该树结构如下:

    第一次询问:2、4的最近公共祖先,故为4。

    第二次询问:3、2的最近公共祖先,故为4。

    第三次询问:3、5的最近公共祖先,故为1。

    第四次询问:1、2的最近公共祖先,故为4。

    第五次询问:4、5的最近公共祖先,故为4。

    故输出依次为4、4、1、4、4。

    #include <bits/stdc++.h>
    inline void read(int &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
    inline void read(long long &x){x = 0;char ch = getchar();char c = ch;while(ch > '9' || ch < '0')c = ch, ch = getchar();while(ch <= '9' && ch >= '0')x = x * 10 + ch - '0', ch = getchar();if(c == '-')x = -x;}
    const int INF = 0x3f3f3f3f;
    const int MAXN = 500000 + 10;
    const int MAXM = 500000 + 10;
    
    long long n,m,root;
    
    struct Edge
    {
    	int u,v,next;
    }edge[(MAXN << 1) + 10];
    int head[MAXN],cnt;
    inline void insert(int a,int b){edge[++cnt] = Edge{a,b,head[a]};head[a] = cnt;}
    
    struct qEdge
    {
    	int u,v,next,ans;
    }qedge[(MAXM << 1) + 20];
    int qhead[MAXM], qcnt;
    inline void qinsert(int a,int b){qedge[++qcnt] = qEdge{a,b,qhead[a],0};qhead[a] = qcnt;}
    
    int tmp1,tmp2;
    
    bool b[MAXN];
    int fa[MAXN];
    
    //并查集
     
    int find(int x)
    {
    	return x == fa[x] ? fa[x] : fa[x] = find(fa[x]);
    }
     
    void merge(int a, int b)
    {
    	int tmp1 = find(a);int tmp2 = find(b);
    	if(tmp1 == tmp2)
    	{
    		return;
    	}
    	else
    	{
    		fa[tmp2] = find(tmp1); 
    	}
    }
    
    void dfs(int u)
    {
    	for(int pos = head[u];pos;pos = edge[pos].next)
    	{
    		int v = edge[pos].v;
    		if(!b[v])
    		{
    			b[v] = true;
    			dfs(v);
    			merge(u, v);//把v指向u合并 
    		}
    	}
    	for(int pos = qhead[u];pos;pos = qedge[pos].next)
    	{
    		int v = qedge[pos].v;
    		if(b[v])
    		{
    			int tmp = find(v);
    			qedge[pos].ans = tmp;
    			if(pos & 1)
    			{
    				qedge[pos + 1].ans = tmp;
    			}
    			else
    			{
    				qedge[pos - 1].ans = tmp;
    			}
    		}
    	}
    }
    
    void tarjan()
    {
    	for(int i = 1;i <= n;i ++)
    	{
    		fa[i] = i;
    	}
    	b[root] = true;
    	dfs(root);
    }
    int main()
    {
    	read(n);read(m);read(root);
    	for(int i = 1;i < n;i ++)
    	{
    		read(tmp1);read(tmp2);
    		insert(tmp1, tmp2);
    		insert(tmp2, tmp1);
    	}
    	for(int i = 1;i <= m;i ++)
    	{
    		read(tmp1);read(tmp2);
    		qinsert(tmp1, tmp2);
    		qinsert(tmp2, tmp1);
    	}
    	tarjan();
    	for(int i = 1;i <= m;i ++)
    	{
    		printf("%d
    ", qedge[i * 2].ans); 
    	}
    	return 0;
    } 
    
  • 相关阅读:
    sublime c/c++ 环境
    sublime编写markdownm
    第八次课程作业
    第七次课程作业
    第六次作业
    第五次课程作业
    Arithmatic项目修改总结
    第四次课程作业
    第三次课程作业
    课程作业二
  • 原文地址:https://www.cnblogs.com/huibixiaoxing/p/7054681.html
Copyright © 2011-2022 走看看