洛谷P3533 [POI2012]RAN-Rendezvous

题目描述

Byteasar is a ranger who works in the Arrow Cave - a famous rendezvous destination among lovers.

The cave consists of nn chambers connected with one-way corridors.

In each chamber exactly one outgoing corridor is marked with an arrow.

Every corridor leads directly to some (not necessarily different) chamber.

The enamoured couples that agree to meet in the Arrow Cave are notorious for forgetting to agree upon specific chamber, and consequently often cannot find their dates.

In the past this led to many mix-ups and misunderstandings\dots But ever since each chamber is equipped with an emergency telephone line to the ranger on duty, helping the enamoured find their dates has become the rangers' main occupation.

The rangers came up with the following method.

Knowing where the enamoured are, they tell each of them how many times they should follow the corridor marked with an arrow in order to meet their date.

The lovers obviously want to meet as soon as possible - after all, they came to the cave to spend time together, not to wander around alone!

Most rangers are happy to oblige: they do their best to give each couple a valid pair of numbers such that their maximum is minimal.

But some rangers, among their numbers Byteasar, grew tired of this extracurricular activity and ensuing puzzles. Byteasar has asked you to write a program that will ease the process. The program, given a description of the cave and the current location of kk couples, should determine kk pairs of numbers x_ixi​ and y_iyi​ such that if the ii -th couple follows respectively: he x_ixi​ and she y_iyi​ corridors marked with arrows,then they will meet in a single chamber of the cave max(x_i,y_i)max(xi​,yi​) is minimal,subject to above min(x_i,y_i)min(xi​,yi​) is minimal,if above conditions do not determine a unique solution, then the woman should cover smaller distance ( x_i\ge y_ixi​≥yi​ ).

扫描二维码关注公众号,回复: 2658658 查看本文章

It may happen that such numbers x_ixi​ and y_iyi​ do not exist - then let x_i=y_i=-1xi​=yi​=−1 . Note that it is fine for several couples to meet in a single chamber. Once the lovers have found their dates, they will be happy to lose themselves in the cave again...

给定一棵内向森林,多次给定两个点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

输入输出格式

输入格式:

In the first line of the standard input there are two positive integers nn and kk ( 1\le n,k\le 500\ 0001≤n,k≤500 000 ), separated by a single space, that denote the number of chambers in the Arrow Cave and the number of couples who want to find their dates, respectively.

The chambers are numbered from 1 to nn , while the enamoured couples are numbered from 1 to kk .

The second line of input contains nn positive integers separated by single spaces:

the ii -th such integer determines the number of chamber to which the corridor marked with an arrow going out of chamber ii leads.

The following kk lines specify the queries by the separated couples. Each such query consists of two positive integers separated by a single space - these denote the numbers of chambers where the lovers are - first him, then her.

In the tests worth 40% of the total points it additionally holds that n,k\le 2\ 000n,k≤2 000 .

输出格式:

Your program should print exactly kk lines to the standard output, one line per each couple specified in the input:

the ii -th line of the output should give the instructions for the ii -th couple on the input.

I.e., the ii -th line of output should contain the integers x_i,y_ixi​,yi​ , separated by a single space.

输入输出样例

输入样例#1: 复制

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

输出样例#1: 复制

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

说明

给定一棵内向森林,多次给定两个点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

题解:

n个点n条边保证了它是一个基环树(每个连通块都有唯一一个环)

然后转自PoPoQQQ:

如果a和b不在同一棵内向树上,显然无解,否则一定有解

定义根为从一个点出发能走到的第一个环上点,如果a和b的根相同,则到达LCA是最优的

否则到达的点一定是a的根和b的根中的一个,两种情况都计算一下,取最优解即可

《倍增LCA万年写不对系列》

题外话:

调了半天发现连样例都有好几个不对,又输出了半天发现是a和b的根相同的情况炸了。

怎么可能?!

然后我眼睛一斜:

我艹!!!

然后闷声改完,一次ac。

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m,n1,a[1000001],g[1000001],dep[1000001],rt[1000001],size[1000001],pos[1000001],f[500001][21],ha[1000001];
void dfs(int x){
	//printf("%d\n",x);
	int i,j=1;
	g[x]=n1;
	if(g[a[x]]==n1){
		for(i=x;j==1||i!=x;i=a[i],j++){
			ha[i]=n1;
			pos[i]=j;
			rt[i]=i;
			dep[i]=1;
		}
		size[n1]=j-1;
		return;
	}
	if(!g[a[x]])dfs(a[x]);
	if(!pos[x]){
		//printf("%d %d\n",x,a[x]);
		f[x][0]=a[x];
		dep[x]=dep[a[x]]+1;
		rt[x]=rt[a[x]];
	}
}
int lca(int x,int y){
	int i;
	//printf("%d\n",x);
	if(dep[x]<dep[y])swap(x,y);
	for(i=20;i>=0;i--)
	 if(dep[f[x][i]]>=dep[y])x=f[x][i];
	//printf("%d %d %d %d\n",x,y,dep[x],dep[y]); 
	if(x==y)return x;
	for(i=20;i>=0;i--)
	 if(f[x][i]!=f[y][i]){
	 	x=f[x][i];y=f[y][i];
	 }
	return f[x][0]; 
}
int go(int x,int y,int z){
	if(pos[y]>pos[x])return pos[y]-pos[x];
	 else return pos[y]+size[z]-pos[x];
}
void solve(int a,int b){
	int x1,y1,x2,y2,x;
	if(g[rt[a]]!=g[rt[b]])
	{
		printf("-1 -1\n");
		return;
	}
	if(rt[a]==rt[b]){
		x=lca(a,b);
		printf("%d %d\n",dep[a]-dep[x],dep[b]-dep[x]);
		return;
	}
	//printf("%d %d %d %d\n",a,b,rt[a],rt[b]);
	x1=dep[a]-1+go(rt[a],rt[b],g[rt[a]]);y1=dep[b]-1;
	x2=dep[a]-1;y2=dep[b]-1+go(rt[b],rt[a],g[rt[a]]);
	if(max(x1,y1)<max(x2,y2)){
		printf("%d %d\n",x1,y1);
	}
	 else if(max(x1,y1)>max(x2,y2))printf("%d %d\n",x2,y2);
	  else if(min(x1,y1)<min(x2,y2))printf("%d %d\n",x1,y1);
	   else if(min(x1,y1)>min(x2,y2))printf("%d %d\n",x2,y2);
	    else printf("%d %d\n",max(x1,y1),min(x1,y1));
}
int main(){
	int i,j,t,k;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)scanf("%d",&a[i]);
	for(i=1;i<=n;i++)
	 if(!g[i]){
	 	n1++;
	 //	printf("%d %d\n",i,n1);
	 	dfs(i);
	 }
	 //printf("-1\n");
	for(j=1;j<=20;j++)
	 for(i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1]; 
	while(m--){
		scanf("%d%d",&t,&k);
		solve(t,k);
	} 
}

猜你喜欢

转载自blog.csdn.net/qq_41510496/article/details/81149805