HDU 5266 pog loves szh III(区间LCA)
题目链接 pog loves szh III
题意就是 求一个区间所有点的$LCA$。
我们把$1$到$n$的$DFS$序全部求出来……然后设$i$的$DFS$序为$c[i]$,$pc[i]$为$c[i]$的反函数。
区间的$LCA$其实就是,$DFS$序最大和最小的两个点的$LCA$。
(话说$2017$女生赛里面有一题要用的结论和这题的差不多)
然后求出区间的$DFS$序最大值$x$和最小值$y$。
然后求一下$LCA(pc[x],pc[y])$即可。
#include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for (int i(a); i <= (b); ++i) #define dec(i, a, b) for (int i(a); i >= (b); --i) typedef long long LL; const int N = 300010; const int A = 21; int c[N]; int deep[N]; int f[N][A], g[N][A], st[N][A]; vector <int> v[N]; int ti; int n, q; int pc[N]; void ST(){ rep(i, 1, n) f[i][0] = c[i]; rep(j, 1, 20) rep(i, 1, n) if ((i + (1 << j) - 1) <= n) f[i][j] = min(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]); rep(i, 1, n) g[i][0] = c[i]; rep(j, 1, 20) rep(i, 1, n) if ((i + (1 << j) - 1) <= n) g[i][j] = max(g[i][j - 1], g[i + (1 << (j - 1))][j - 1]); } inline int solvemin(int l, int r){ int k = (int)log2((double)(r - l + 1)); return min(f[l][k], f[r - (1 << k) + 1][k]); } inline int solvemax(int l, int r){ int k = (int)log2((double)(r - l + 1)); return max(g[l][k], g[r - (1 << k) + 1][k]); } void dfs(int x, int fa, int dep){ c[x] = ++ti; pc[ti] = x; deep[x] = dep; if (fa){ st[x][0] = fa; for (int i = 0; st[st[x][i]][i]; ++i) st[x][i + 1] = st[st[x][i]][i]; } for (auto u : v[x]){ if (u == fa) continue; dfs(u, x, dep + 1); } } int LCA(int a, int b){ if (deep[a] < deep[b]) swap(a, b); for (int i = 0, delta = deep[a] - deep[b]; delta; delta >>= 1, ++i) if (delta & 1) a = st[a][i]; if (a == b) return a; dec(i, 19, 0) if (st[a][i] != st[b][i]) a = st[a][i], b = st[b][i]; return st[a][0]; } int main(){ while (~scanf("%d", &n)){ rep(i, 0, n + 1) v[i].clear(); memset(c, 0, sizeof c); ti = 0; rep(i, 2, n){ int x, y; scanf("%d%d", &x, &y); v[x].push_back(y); v[y].push_back(x); } memset(st, 0, sizeof st); memset(f, 0, sizeof f); memset(g, 0, sizeof g); dfs(1, 0, 0); ST(); for (scanf("%d", &q); q--; ){ int x, y; scanf("%d%d", &x, &y); printf("%d\n", LCA(pc[solvemax(x, y)], pc[solvemin(x, y)])); } } return 0; }