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;
}