CodeForces 1706E Qpwoeirut and Vertices

洛谷传送门

CF 传送门

思路

考虑将每条边的编号作为边权,然后建 \(\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;
}
posted @ 2022-07-28 20:55  zltzlt  阅读(28)  评论(0编辑  收藏  举报