CodeForces 1706E Qpwoeirut and Vertices
思路
考虑将每条边的编号作为边权,然后建 \(\mathrm{Kruskal}\) 重构树。
那么每个询问的答案即为 \(\mathrm{LCA}(l,l+1,...,r-1,r)\)。
有一个经典套路,就是多个点的 \(\mathrm{LCA}\) 就是 \(\mathrm{dfs}\) 序最小的点和 \(\mathrm{dfs}\) 序最大的点的 \(\mathrm{LCA}\)。
于是随便线段树维护一下即可。
时间复杂度 \(O(m \log m + q \log n)\)。
代码
code
/*
p_b_p_b txdy
AThousandMoon txdy
AThousandSuns txdy
hxy txdy
*/
#include <bits/stdc++.h>
#define pb push_back
#define fst first
#define scd second
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
const int maxn = 300100;
const int logn = 20;
int n, m, q, head[maxn], len, ffa[maxn], val[maxn];
int f[maxn][logn], g[maxn][logn], lg[maxn];
int fa[maxn], sz[maxn], son[maxn], dep[maxn];
int top[maxn], dfn[maxn], times, rnk[maxn];
bool vis[maxn];
struct edge {
int to, next;
} edges[maxn << 2];
void add_edge(int u, int v) {
edges[++len].to = v;
edges[len].next = head[u];
head[u] = len;
}
int find(int x) {
return ffa[x] == x ? x : ffa[x] = find(ffa[x]);
}
int dfs(int u, int f, int d) {
sz[u] = 1;
fa[u] = f;
dep[u] = d;
dfn[u] = ++times;
rnk[times] = u;
int maxson = -1;
for (int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (v == f) {
continue;
}
sz[u] += dfs(v, u, d + 1);
if (sz[v] > maxson) {
son[u] = v;
maxson = sz[v];
}
}
return sz[u];
}
void dfs2(int u, int tp) {
top[u] = tp;
vis[u] = 1;
if (!son[u]) {
return;
}
dfs2(son[u], tp);
for (int i = head[u]; i; i = edges[i].next) {
int v = edges[i].to;
if (vis[v]) {
continue;
}
dfs2(v, v);
}
}
int querylca(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) {
swap(x, y);
}
x = fa[top[x]];
}
if (dep[x] > dep[y]) {
swap(x, y);
}
return x;
}
int qmax(int l, int r) {
int k = lg[r - l + 1];
return max(f[l][k], f[r - (1 << k) + 1][k]);
}
int qmin(int l, int r) {
int k = lg[r - l + 1];
return min(g[l][k], g[r - (1 << k) + 1][k]);
}
void solve() {
len = times = 0;
lg[0] = -1;
for (int i = 1; i < maxn; ++i) {
lg[i] = lg[i >> 1] + 1;
}
scanf("%d%d%d", &n, &m, &q);
for (int i = 1; i <= n * 2; ++i) {
ffa[i] = i;
head[i] = 0;
vis[i] = 0;
val[i] = 0;
son[i] = 0;
}
int tot = n;
for (int i = 1, u, v; i <= m; ++i) {
scanf("%d%d", &u, &v);
int x = find(u), y = find(v);
if (x != y) {
int z = ++tot;
ffa[x] = ffa[y] = z;
add_edge(z, x);
add_edge(z, y);
val[z] = i;
}
}
dfs(tot, -1, 1);
dfs2(tot, tot);
for (int i = 1; i <= n; ++i) {
f[i][0] = g[i][0] = dfn[i];
}
for (int j = 1; (1 << j) <= n; ++j) {
for (int i = 1; i + (1 << j) - 1 <= n; ++i) {
f[i][j] = max(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
g[i][j] = min(g[i][j - 1], g[i + (1 << (j - 1))][j - 1]);
}
}
while (q--) {
int l, r;
scanf("%d%d", &l, &r);
int xx = rnk[qmin(l, r)], yy = rnk[qmax(l, r)];
printf("%d ", val[querylca(xx, yy)]);
}
putchar('\n');
}
int main() {
int T = 1;
scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}