P3533

P3533 [POI 2012] RAN-Rendezvous

题目描述

译自 POI 2012 Stage 1. 「Rendezvous

给定一个有 \(n\) 个顶点的有向图,每个顶点有且仅有一条出边。每次询问给出两个顶点 \(a_i\)\(b_i\),求满足以下条件的 \(x_i\)\(y_i\)

  • 从顶点 \(a_i\) 沿出边走 \(x_i\) 步与从顶点 \(b_i\) 沿出边走 \(y_i\) 步到达的顶点相同。
  • \(\max(x_i, y_i)\) 最小。
  • 满足以上条件的情况下 \(\min(x_i, y_i)\) 最小。
  • 如果以上条件没有给出一个唯一的解,则还需要满足 \(x_i \ge y_i\).

如果不存在这样的 \(x_i\)\(y_i\),则 \(x_i = y_i = -1\).

输入 #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

对于 \(100\%\) 的数据,\(1 \le n \le 500\ 000,1 \le k \le 500\ 000\).

若两个点所在连通图里面没有环,则显然答案就是LCA

如果有环,分两种情况讨论

  1. 两个点都在环上面
  2. 两个点都不在环上面
  3. 其中一个点在环上面

为了方便判断,直接写一个 check 函数即可。
代码比较阴间。

#include<bits/stdc++.h>
#define N 505050
#define rep(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int cnt[N],n,m,fa[N][22],len[N],R[1114514];
int tot;
vector<int>G[N];
int root[1145141];
int dep[1145141],step[1145141];
void dfs(int u,int f,int rt) {
	dep[u]=dep[f]+1;
	root[u]=rt;
	for(int i=0;i<G[u].size();i++) {
		int v=G[u][i];
		if(cnt[v]||v==f) continue;
		dfs(v,u,rt);
	}
}

inline int read() {
	int res=0,fs=1;
	char c=getchar();
	while(!(c>='0'&&c<='9')) {
		if(c=='-') fs=-1;
		c=getchar();
	}
	
	while(c>='0'&&c<='9') {
		res=res*10+c-'0';
		c=getchar();
	}
	
	return res*fs;
}
 

int lca(int x,int y) {
	if(dep[x]<dep[y]) swap(x,y);
	int tmp=dep[x]-dep[y];
	
	for(int i=19;i>=0;i--) {
		if(tmp>>i&1) x=fa[x][i];
	}
	
	if(x==y) return y;
	
	for(int i=19;i>=0;i--) {
		if(fa[x][i]!=fa[y][i]) {
			x=fa[x][i];
			y=fa[y][i];
		}
	}
	return fa[x][0];
}

bool check(int a,int b,int c,int d){
    if(max(a,b)!=max(c,d))return max(a,b)<max(c,d);
    if(min(a,b)!=min(c,d))return min(a,b)<min(c,d);
    return a>=b;
}
void round(int u,int id,int st) {
	if(step[u]) return ;
	R[u]=id;len[id]++;
	step[u]=st;
	round(fa[u][0],id,st+1);
}
signed main() {
	cin>>n>>m;
	for(int i=1;i<=n;i++) {
		int u=read();
		G[u].push_back(i);
		fa[i][0]=u;
		cnt[u]++;
	}
	queue<int>q;
	rep(i,1,n) 
		if(!cnt[i]) q.push(i); 
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		int v=fa[u][0];
		cnt[v]--;
		if(cnt[v]==0) 
			q.push(v);
	}
	rep(i,1,n) {
		if(cnt[i]) {
			dfs(i,0,i);
			if(!step[i]) {
				tot++;
				round(i,tot,1);
			}
		}
	}
	rep(p,1,19)
	    rep(i,1,n){ 
	        fa[i][p]=fa[fa[i][p-1]][p-1];
	    }
	while(m--) {
		int u=read(),v=read();
		if(R[root[u]]!=R[root[v]]){
			cout<<-1<<' '<<-1<<'\n';
		} else if(root[u]==root[v]) {
			int l=lca(u,v);
			cout<<dep[u]-dep[l]<<' '<<dep[v]-dep[l]<<'\n';
		} else {
			
        	int t1=root[u],t2=root[v];
            int ans1=dep[u]+(step[t2]-step[t1]+len[R[t1]])%len[R[t1]],ans2=dep[v]+(step[t1]-step[t2]+len[R[t1]])%len[R[t1]];
			if(check(dep[u],ans2,ans1,dep[v]))cout<<dep[u]-1<<' '<<ans2-1<<endl;
            else cout<<ans1-1<<' '<<dep[v]-1<<endl;
		}
	}
	return 0;
}
posted @ 2025-03-20 21:59  houpingze  阅读(11)  评论(1)    收藏  举报