4539: [Hnoi2016]树
4539: [Hnoi2016]树
分析:
主席树+倍增。
代码:
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cmath> #include<cctype> #include<set> #include<queue> #include<vector> #include<map> #define pa pair<int,int> using namespace std; typedef long long LL; #define int LL inline int read() { int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; } const int N = 100005; struct Edge { int to, nxt; } e[N << 1]; struct OPT { int l, r, fa, rt; } q[N]; int head[N], dfn[N], st[N], ed[N], pos[N], fa[N][20], siz[N], f[N][20], g[N][20], d1[N], d2[N]; set< pa > s; int En, Index, NowIndex, n; inline void add_edge(int u,int v) { ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En; ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En; } struct SegmentTree{ int sum[N * 20], ls[N * 20], rs[N * 20], Root[N], TreeIndex; void Insert(int l,int r,int &now,int pre,int p) { if (!now) now = ++TreeIndex; sum[now] = sum[pre] + 1; if (l == r) return ; int mid = (l + r) >> 1; if (p <= mid) { rs[now] = rs[pre]; Insert(l, mid, ls[now], ls[pre], p); } else { ls[now] = ls[pre]; Insert(mid + 1, r, rs[now], rs[pre], p); } } int query(int l,int r,int H,int T,int k) { if (l == r) return l; int mid = (l + r) >> 1; if (k <= sum[ls[T]] - sum[ls[H]]) return query(l, mid, ls[H], ls[T], k); else return query(mid + 1, r, rs[H], rs[T], k - (sum[ls[T]] - sum[ls[H]])); } }T; void dfs(int u) { d1[u] = d1[fa[u][0]] + 1; st[u] = ++Index; pos[Index] = u; siz[u] = 1; for (int i = 1; i <= 19; ++i) fa[u][i] = fa[fa[u][i - 1]][i - 1]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa[u][0]) continue; fa[v][0] = u; dfs(v); siz[u] += siz[v]; } ed[u] = Index; } int LCA1(int u,int v) { if (d1[u] < d1[v]) swap(u, v); int d = d1[u] - d1[v]; for (int i = 19; ~i; --i) if ((d >> i) & 1) u = fa[u][i]; if (u == v) return u; for (int i = 19; ~i; --i) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i]; return fa[u][0]; } int getdis(int x,int y) { return d1[x] + d1[y] - d1[LCA1(x, y)] * 2; } void add(int id) { int x = read(), y = read(), z; q[id].l = NowIndex, q[id].r = (NowIndex += siz[x]) - 1, q[id].rt = x; set< pa > :: iterator it = s.lower_bound(pa(y, 0)); z = q[it->second].rt; q[id].fa = T.query(1, n, T.Root[st[z] - 1], T.Root[ed[z]], y - q[it->second].l + 1); f[id][0] = it->second, g[id][0] = getdis(q[id].fa, z) + 1; d2[id] = d2[it->second] + 1; for (int i = 1; i <= 19; ++i) f[id][i] = f[f[id][i - 1]][i - 1], g[id][i] = g[id][i - 1] + g[f[id][i - 1]][i - 1]; s.insert(pa(q[id].r, id)); } int LCA2(int u,int v,int tu,int tv) { if (d2[u] < d2[v]) swap(u, v), swap(tu, tv); int ans = 0, t = u, d = d2[u] - d2[v]; for (int i = 19; ~i; --i) if ((d >> i) & 1) ans += g[u][i], u = f[u][i]; if (u == v) { d --; ans = 0; u = t; for (int i = 19; ~i; --i) if ((d >> i) & 1) ans += g[t][i], t = f[t][i]; ans += getdis(q[t].fa, tv) + 1 + getdis(tu, q[u].rt); return ans; } ans += getdis(tu, q[t].rt) + getdis(tv, q[v].rt); for (int i = 19; ~i; --i) if (f[u][i] != f[v][i]) ans += g[u][i] + g[v][i], u = f[u][i], v = f[v][i]; ans += getdis(q[u].fa, q[v].fa) + 2; return ans; } void Ask() { int u = read(), v = read(), ans, iu, iv, tu, tv; iu = s.lower_bound(pa(u, 0))->second, iv = s.lower_bound(pa(v, 0))->second; tu = T.query(1, n, T.Root[st[q[iu].rt] - 1], T.Root[ed[q[iu].rt]], u - q[iu].l + 1); tv = T.query(1, n, T.Root[st[q[iv].rt] - 1], T.Root[ed[q[iv].rt]], v - q[iv].l + 1); if (iu != iv) ans = LCA2(iu, iv, tu, tv); else ans = getdis(tu, tv); printf("%lld\n", ans); } signed main() { n = read();int m = read(), Q = read(); for (int i = 1; i < n; ++i) add_edge(read(), read()); dfs(1); for (int i = 1; i <= n; ++i) T.Insert(1, n, T.Root[i], T.Root[i - 1], pos[i]); NowIndex = n + 1; s.insert(pa(n, 1)); q[1].l = 1, q[1].r = n, q[1].rt = 1, q[1].fa = 0; for (int i = 1; i <= m; ++i) add(i + 1); while (Q --) Ask(); return 0; }