HDU 4297--One and One Story(LCA&并查集)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4297--One and One Story(LCA&并查集)相关的知识,希望对你有一定的参考价值。

One and One Story

Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others)
Total Submission(s): 1049 Accepted Submission(s): 459


Problem Description
  Have you ever played the romantic Flash game, "One and One Story"?1 In this story of a boy and a girl and their romance you are to direct them to meet together as they face their euphoria and trials of their relationship.
  You, as a member of the FFF Inquisition, 2 are fed up with such game since you believe that to make things fair, you should not keep providing guidance information while risking remaining forever alone 3 . So you decided to write a program working out guidance for these sweet small lovers on behalf of you. ( Another reason is, you have to help K couples, which would make you somewhat overwhelmed. )
  Fortunately, you are to handle not the Flash game above, but a simplified version: In the game, a maze consists of some rooms connected with one-way hallways. For each room, there is exactly one outgoing hallway here, and it would lead directly to some room (not necessarily a different one). The boy and girl are trapped in (not necessarily different) rooms. In each round of the games, both of them could choose to stay in the current room or walk to the room to which the unique outgoing hallway leads. Note that boy and girl could act independently of each other. Your goal is to come to the reunion between them.
  Your program should determine a pair of numbers (A,B) for each couple of boy and girl, where A represents number of hallway the boy walked through, B the girl, that could lead reunion between them. First, your program should minimize max(A,B). If there are several solutions, you should then guarantee that min(A,B) is minimized subject to above. If, satisfying above conditions, there are still multiple solutions, girl should walk less, that is you should then keep A >= B subject to conditions above.
  In case they could not reunion, just let A = B = -1.
 
Input
  There‘re several test cases.
  In each test case, in the first line there are two positive integers N and K (1 <= N <= 500000; 1 <= K <= 500000) denoting the number of rooms and number of couples. Rooms a numbered from 1 to N.
  The second line contains n positive integers: the ith integer denotes the number of room to which the hallway going out of room i leads.
The following K lines are queries of several couples. Each query consists of two positive integers in a single line denoting the numbers of rooms where the lovers currently are: first the boy, then the girl.
  Please process until EOF (End Of File).
 
Output
  For each test case you should output exactly K lines, one line per query. Each line consists two integers separated by a space: the integer A and B for this couple.
  See samples for detailed information.
 
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
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
2 3
1 2
2 2
0 1
-1 -1
 

题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4297 

Solution

    画图发现,实际上这个有向图是一个森林。

    首先-1的情况可以用并查集判掉。。

    剩下的每一个分离的有向图都可以看做一颗以一个环为根的树。。

      然后分两种情况讨论:

        1. 两个节点在根的同一颗子树中,那么直接LCA

        2. 其余情况,肯定要两个点都先走到环上,然后判断一下就好了。。。

代码

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define LL long long
#define N 500050
using namespace std;
inline int Read_(){
	int x=0,f=1;char ch=getchar();
	while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();}
	while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
	return x*f;
}
int n,k,cnt=0,tot=0;
int fa[N],hed[N],dep[N],cir[N],rt[N],g[N],num[N],len[N];
int F[N][22];
bool vis[N];
struct edge{
	int r,nxt;
}e[N];
void insert_(int u,int v){
	e[++cnt].r=v;e[cnt].nxt=hed[u];hed[u]=cnt;
}
int find_(int x){
	return fa[x]==x?x:fa[x]=find_(fa[x]);
}
void dfs(int x){
	for(int i=1;i<=20;i++)
		F[x][i]=F[F[x][i-1]][i-1];
	for(int i=hed[x];i;i=e[i].nxt)
		if(!vis[e[i].r]){
			dep[e[i].r]=dep[x]+1;
			rt[e[i].r]=rt[x];
			F[e[i].r][0]=x;
			vis[e[i].r]=1;
			dfs(e[i].r);
		}
	return;
}
int lca_(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=0;(1<<i)<=(dep[x]-dep[y]);i++)
		if( (1<<i)&(dep[x]-dep[y]) ) x=F[x][i];
	if(x==y) return x;
	for(int 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 main(){
	int u,v,w;
	while(scanf("%d%d",&n,&k)!=EOF){
		cnt=0;tot=0;
		memset(hed,0,sizeof(hed));
		memset(vis,0,sizeof(vis));
		memset(F,0,sizeof(F));
		memset(num,0,sizeof(num));
		for(int i=1;i<=n;i++) fa[i]=i;
		for(int i=1;i<=n;i++){
			g[i]=Read_();insert_(g[i],i);
			u=find_(i);v=find_(g[i]);
			if(u!=v) fa[u]=v;
			else cir[++tot]=i;
		}
		for(int i=1;i<=tot;i++){
			int js=1;
			u=cir[i];dep[u]=0;rt[u]=u;vis[u]=1;num[u]=js;u=g[u];
			while(u!=cir[i]){
				js++;dep[u]=0;rt[u]=u;vis[u]=1;num[u]=js;u=g[u];
			}
			len[find_(u)]=js;
			dfs(u);u=g[u];
			while(u!=cir[i]){
				dfs(u);u=g[u];
			}
		}
		for(int i=1;i<=k;i++){
			u=Read_();v=Read_();
			if(find_(u)!=find_(v)){
				printf("-1 -1\n");
				continue;
			}
			if(rt[u]==rt[v]){
				w=lca_(u,v);
				printf("%d %d\n",dep[u]-dep[w],dep[v]-dep[w]);
				continue;
			}
			int ansu,ansv,ansU,ansV;
			if(num[rt[u]]<num[rt[v]]){
				ansu=dep[u]+num[rt[v]]-num[rt[u]];
				ansv=dep[v];
				ansU=dep[u];
				ansV=dep[v]+len[find_(v)]-num[rt[v]]+num[rt[u]];
				if(max(ansu,ansv)<max(ansU,ansV)){
					printf("%d %d\n",ansu,ansv);continue;
				}
				if(max(ansu,ansv)>max(ansU,ansV)){
					printf("%d %d\n",ansU,ansV);continue;
				}
				if(min(ansu,ansv)<min(ansU,ansV)){
					printf("%d %d\n",ansu,ansv);continue;
				}
				if(min(ansu,ansv)>min(ansU,ansV)){
					printf("%d %d\n",ansU,ansV);continue;
				}
				if(ansv<ansV){
					printf("%d %d\n",ansu,ansv);continue;
				}
				else{
					printf("%d %d\n",ansU,ansV);continue;
				}
			}
			else {
				ansu=dep[u];
				ansv=dep[v]+num[rt[u]]-num[rt[v]];
				ansU=dep[u]+len[find_(u)]-num[rt[u]]+num[rt[v]];
				ansV=dep[v];
				if(max(ansu,ansv)<max(ansU,ansV)){
					printf("%d %d\n",ansu,ansv);continue;
				}
				if(max(ansu,ansv)>max(ansU,ansV)){
					printf("%d %d\n",ansU,ansV);continue;
				}
				if(min(ansu,ansv)<min(ansU,ansV)){
					printf("%d %d\n",ansu,ansv);continue;
				}
				if(min(ansu,ansv)>min(ansU,ansV)){
					printf("%d %d\n",ansU,ansV);continue;
				}
				if(ansv<ansV){
					printf("%d %d\n",ansu,ansv);continue;
				}
				else{
					printf("%d %d\n",ansU,ansV);continue;
				}
			}
		}
	}
	return 0;
}

  

  

This passage is made by Iscream-2001.

 

以上是关于HDU 4297--One and One Story(LCA&并查集)的主要内容,如果未能解决你的问题,请参考以下文章

HDU4283 You Are the One

APP One Link ,android and ios qrcode merge as One QRCode and one short link

hdu 4283You Are the One

HDU 3131 One…Two…Five! (暴力搜索)

HDU 4283---You Are the One(区间DP)

HDU 5358 多校第6场 First One