POI2012RAN-Rendezvous
POI #Year2012 #基环树 #lca
分类讨论
- 如果 不联通,
- 如果 在同一棵子树下,最优策略一定是
- 如果 不在同一棵子树下,最优策略是 中的一个
// 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; }
本文作者:xiaruize's Blog
本文链接:https://www.cnblogs.com/xiaruize/p/18156736
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步