zoukankan      html  css  js  c++  java
  • 【BZOJ2791】[Poi2012]Rendezvous 倍增

    【BZOJ2791】[Poi2012]Rendezvous

    Description

    给定一个n个顶点的有向图,每个顶点有且仅有一条出边。
    对于顶点i,记它的出边为(i, a[i])。
    再给出q组询问,每组询问由两个顶点a、b组成,要求输出满足下面条件的x、y:
    1. 从顶点a沿着出边走x步和从顶点b沿着出边走y步后到达的顶点相同。
    2. 在满足条件1的情况下max(x,y)最小。
    3. 在满足条件1和2的情况下min(x,y)最小。
    4. 在满足条件1、2和3的情况下x>=y。
    如果不存在满足条件1的x、y,输出-1 -1。

    Input

    第一行两个正整数n和q (n,q<=500,000)。
    第二行n个正整数a[1],a[2],...,a[n] (a[i]<=n)。
    下面q行,每行两个正整数a,b (a,b<=n),表示一组询问。

    Output

    输出q行,每行两个整数。

    Sample Input

    12 5
    4 3 5 5 1 1 12 12 9 9 7 1
    7 2
    8 11
    1 2
    9 10
    10 5

    Sample Output

    2 3
    1 2
    2 2
    0 1
    -1 -1

    题解:由于给出的是个基环树森林,所以我们考虑如下几种情况。

    1.最终不会走到一个环上,-1。
    2.还没走到环上就相遇,那么我们用倍增,当成树上LCA来处理即可。
    3.走到环上才相遇,那么相遇点一定是两人刚走到环上时的两个点中的一个,判一下即可。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <vector>
    using namespace std;
    const int maxn=500010;
    int n,m,sum,cnt;
    int r[20][maxn],to[maxn],next[maxn],head[maxn],Log[maxn],bel[maxn],pos[maxn],len[maxn],toc[maxn],d[maxn];
    queue<int> q;
    vector<int> v[maxn];
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    inline int lca(int a,int b)
    {
    	if(d[a]<d[b])	swap(a,b);
    	for(int i=Log[d[a]-d[b]];i>=0;i--)	if(d[r[i][a]]>=d[b])	a=r[i][a];
    	if(a==b)	return a;
    	for(int i=Log[d[a]];i>=0;i--)	if(r[i][a]!=r[i][b])	a=r[i][a],b=r[i][b];
    	return r[0][a];
    }
    inline bool cmp(int x1,int y1,int x2,int y2)
    {
    	if(max(x1,y1)!=max(x2,y2))	return max(x1,y1)<max(x2,y2);
    	if(min(x1,y1)!=min(x2,y2))	return min(x1,y1)<min(x2,y2);
    	return x1>=y1;
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')	f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+(gc^'0'),gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd();
    	memset(head,-1,sizeof(head));
    	int i,j,u,a,b,x,y,x1,y1,x2,y2;
    	for(i=1;i<=n;i++)	r[0][i]=rd(),d[r[0][i]]++;
    	for(i=2;i<=n;i++)	Log[i]=Log[i>>1]+1;
    	for(j=1;(1<<j)<=n;j++)	for(i=1;i<=n;i++)	r[j][i]=r[j-1][r[j-1][i]];
    	for(i=1;i<=n;i++)	if(!d[i])	q.push(i);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		d[r[0][u]]--;
    		if(!d[r[0][u]])	q.push(r[0][u]);
    	}
    	for(i=1;i<=n;i++)	if(d[i]&&!bel[i])
    		for(sum++,j=i;!bel[j];j=r[0][j])	pos[j]=++len[sum],bel[j]=sum;
    	for(i=1;i<=n;i++)
    	{
    		if(bel[i])	d[i]=0,toc[i]=i,q.push(i);
    		else	add(r[0][i],i);
    	}
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])	d[to[i]]=d[u]+1,toc[to[i]]=toc[u],q.push(to[i]);
    	}
    	for(i=1;i<=m;i++)
    	{
    		a=rd(),b=rd();
    		if(bel[toc[a]]!=bel[toc[b]])	printf("-1 -1
    ");
    		else	if(toc[a]==toc[b])
    		{
    			x=lca(a,b);
    			printf("%d %d
    ",d[a]-d[x],d[b]-d[x]);
    		}
    		else
    		{
    			x=d[a],a=toc[a],y=d[b],b=toc[b];
    			x1=x+(pos[b]-pos[a]+len[bel[a]])%len[bel[a]],y1=y;
    			x2=x,y2=y+(pos[a]-pos[b]+len[bel[b]])%len[bel[b]];
    			if(cmp(x1,y1,x2,y2))	printf("%d %d
    ",x1,y1);
    			else	printf("%d %d
    ",x2,y2);
    		}
    	}
    	return 0;
    }//12 5 4 3 5 5 1 1 12 12 9 9 7 1 7 2 8 11 1 2 9 10 10 5 
  • 相关阅读:
    Vue 封装js 并 引用
    Vue todolist练习 知识点
    Vue 双向数据绑定、事件介绍以及ref获取dom节点
    Vue 目录结构 绑定数据 绑定属性 循环渲染数据
    Vue自学笔记--项目的创建
    sqlalchemy第一部分
    mysql查询补充
    mysql数据库查询操作
    mysql数据库关系操作
    数据表的约束及数据类型操作
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7814389.html
Copyright © 2011-2022 走看看