【省内训练2018-11-23】Graph

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/84449688

【思路要点】

  • 离线询问,为每一条边找到一个删除时间。
  • 将过程倒过来,按照删除时间倒序加入每一条边。
  • 我们将加入的边分为两类,加入后连接两个不同的联通块的称为树边,剩余的边称为非树边。
  • 显然,树边的加入不会产生新的双连通分量,因此,我们可以预先将所有的树边加入图中,并处理出形成的森林中每个节点的深度等信息。
  • 之后,我们每加入一条非树边,就会将森林中一条树链上所有的节点合并起来,可以通过并查集实现。
  • mapmap 配合启发式合并维护颜色集合,时间复杂度 O(NLog2N+M+Q)O(NLog^2N+M+Q)
  • 也可以用线段树合并维护颜色集合,时间复杂度 O(NLogN+M+Q)O(NLogN+M+Q)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e5 + 5;
const int MAXM = 5e5 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
map <int, int> col[MAXN];
vector <int> a[MAXN], adj[MAXN], qry[MAXM];
ll ans[MAXM], curr;
int n, m, k, q, num[MAXN], father[MAXN], depth[MAXN], f[MAXN];
int x[MAXM], y[MAXM], t[MAXM], p[MAXM], timer;
int F(int x) {
	if (f[x] == x) return x;
	else return f[x] = F(f[x]);
}
void dfs(int pos, int fa) {
	f[pos] = pos;
	father[pos] = fa;
	depth[pos] = depth[fa] + 1;
	col[pos][num[pos]] = 1;
	for (auto x : a[pos])
		if (x != fa) dfs(x, pos);
}
ll func(int x) {
	return x * (x - 1ll) / 2;
}
void merge(int x, int y) {
	x = F(x), y = F(y);
	int tx = x, ty = y;
	while (tx != ty) {
		if (depth[tx] > depth[ty]) tx = F(father[tx]);
		else ty = F(father[ty]);
	}
	int lca = tx;
	while (x != lca) {
		if (col[x].size() > col[lca].size()) swap(col[x], col[lca]);
		for (auto val : col[x]) {
			curr -= func(val.second);
			curr -= func(col[lca][val.first]);
			col[lca][val.first] += val.second;
			curr += func(col[lca][val.first]);
		}
		f[x] = F(father[x]);
		x = F(x);
	}
	x = y;
	while (x != lca) {
		if (col[x].size() > col[lca].size()) swap(col[x], col[lca]);
		for (auto val : col[x]) {
			curr -= func(val.second);
			curr -= func(col[lca][val.first]);
			col[lca][val.first] += val.second;
			curr += func(col[lca][val.first]);
		}
		f[x] = F(father[x]);
		x = F(x);
	}
}
int main() {
	read(n), read(m), read(k), read(q);
	for (int i = 1; i <= n; i++)
		read(num[i]);
	for (int i = 1; i <= m; i++) {
		read(x[i]), read(y[i]);
		adj[x[i]].push_back(i);
		adj[y[i]].push_back(i);
	}
	static bool flg[MAXM];
	qry[1].push_back(0);
	for (int i = 1; i <= q; i++) {
		int x; read(x);
		if (!flg[x]) {
			flg[x] = true;
			for (auto y : adj[x])
				if (t[y] == 0) t[y] = ++timer;
		}
		qry[timer + 1].push_back(i);
	}
	for (int i = 1; i <= m; i++)
		if (t[i] == 0) t[i] = ++timer;
	for (int i = 1; i <= m; i++)
		p[t[i]] = i;
	for (int i = 1; i <= n; i++)
		f[i] = i;
	memset(flg, false, sizeof(flg));
	for (int i = m; i >= 1; i--) {
		int now = p[i];
		if (F(x[now]) != F(y[now])) {
			flg[now] = true;
			a[x[now]].push_back(y[now]);
			a[y[now]].push_back(x[now]);
			f[F(x[now])] = F(y[now]);
		}
	}
	for (int i = 1; i <= n; i++)
		if (depth[i] == 0) dfs(i, 0);
	for (int i = m; i >= 1; i--) {
		int now = p[i];
		if (!flg[now]) merge(x[now], y[now]);
		for (auto x : qry[i])
			ans[x] = curr;
	}
	for (int i = 0; i <= q; i++)
		writeln(ans[i]);
	return 0;
}
阅读更多

没有更多推荐了,返回首页