POI2012RAN-Rendezvous

xiaruize發表於2024-04-25

POI #Year2012 #基環樹 #lca

分類討論

  • 如果 \(a,b\) 不聯通, \(-1\)
  • 如果 \(a,b\) 在同一棵子樹下,最優策略一定是 \(lca(a,b)\)
  • 如果 \(a,b\) 不在同一棵子樹下,最優策略是 \(rt_a,rt_b\) 中的一個
// Author: xiaruize
const int N = 5e5 + 10;
#define endl '\n'
int head[N], to[N], nxt[N], egcnt;

void add(int u, int v)
{
	to[++egcnt] = v;
	nxt[egcnt] = head[u];
	head[u] = egcnt;
}

int n, q;
int fa[N][20];
// vector<int> g[N];
int deg[N];
queue<int> que;
int st[N];
int rt[N], num[N];
int dep[N];
int len[N];
int tot = 0;

void dfs(int x, int rot, int dp)
{
	dep[x] = dp;
	rt[x] = rot;
	num[x] = num[rot];
	for (int i = head[x]; i; i = nxt[i])
	{
		int v = to[i];
		if (!deg[v])
			dfs(v, rot, dp + 1);
	}
}

int lca(int u, int v)
{
	if (dep[u] < dep[v])
		swap(u, v);
	per(i, 19, 0) if (dep[fa[u][i]] >= dep[v])
		u = fa[u][i];
	if (u == v)
		return u;
	per(i, 19, 0) if (fa[u][i] != fa[v][i])
	{
		u = fa[u][i];
		v = fa[v][i];
	}
	return fa[u][0];
}

bool cmp(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 solve()
{
	cin >> n >> q;
	rep(i, 1, n)
	{
		cin >> fa[i][0];
		add(fa[i][0], i);
		deg[fa[i][0]]++;
	}
	rep(k, 1, 19)
		rep(i, 1, n)
			fa[i][k] = fa[fa[i][k - 1]][k - 1];
	rep(i, 1, n) if (!deg[i]) que.push(i);
	while (!que.empty())
	{
		auto x = que.front();
		que.pop();
		deg[fa[x][0]]--;
		if (!deg[fa[x][0]])
			que.push(fa[x][0]);
	}
	rep(i, 1, n)
	{
		if (!deg[i])
			continue;
		debug(i);
		if (!num[i])
		{
			num[i] = ++tot;
			int x = fa[i][0];
			st[i] = ++len[tot];
			while (x != i)
			{
				st[x] = ++len[tot];
				num[x] = tot;
				x = fa[x][0];
			}
		}
		dfs(i, i, 0);
	}
	while (q--)
	{
		int u, v;
		cin >> u >> v;
		if (num[u] != num[v])
		{
			cout << "-1 -1" << endl;
			continue;
		}
		if (rt[u] == rt[v])
		{
			int p = lca(u, v);
			cout << dep[u] - dep[p] << ' ' << dep[v] - dep[p] << endl;
		}
		else
		{
			int rt1 = rt[u], rt2 = rt[v];
			int tmp1 = dep[u] + (st[rt2] - st[rt1] + len[num[rt1]]) % len[num[rt1]];
			int tmp2 = dep[v] + (st[rt1] - st[rt2] + len[num[rt1]]) % len[num[rt1]];
			if (cmp(dep[u], tmp2, dep[v], tmp1))
				cout << dep[u] << ' ' << tmp2 << endl;
			else
				cout << tmp1 << ' ' << dep[v] << endl;
		}
	}
}

#ifndef ONLINE_JUDGE
bool end_of_memory_use;
#endif

signed main()
{
	// freopen(".in","r",stdin);
	// freopen(".out","w",stdout);
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int testcase = 1;
	// cin >> testcase;
	while (testcase--)
		solve();
#ifndef ONLINE_JUDGE
	cerr << "Memory use:" << (&end_of_memory_use - &start_of_memory_use) / 1024.0 / 1024.0 << "MiB" << endl;
	cerr << "Time use:" << (double)clock() / CLOCKS_PER_SEC * 1000.0 << "ms" << endl;
#endif
	return 0;
}