1. 程式人生 > >【省內訓練2018-11-23】Graph

【省內訓練2018-11-23】Graph

【思路要點】

  • 離線詢問,為每一條邊找到一個刪除時間。
  • 將過程倒過來,按照刪除時間倒序加入每一條邊。
  • 我們將加入的邊分為兩類,加入後連線兩個不同的聯通塊的稱為樹邊,剩餘的邊稱為非樹邊。
  • 顯然,樹邊的加入不會產生新的雙連通分量,因此,我們可以預先將所有的樹邊加入圖中,並處理出形成的森林中每個節點的深度等資訊。
  • 之後,我們每加入一條非樹邊,就會將森林中一條樹鏈上所有的節點合併起來,可以通過並查集實現。
  • m
    a p map
    配合啟發式合併維護顏色集合,時間複雜度 O ( N L
    o g 2 N + M + Q
    ) O(NLog^2N+M+Q)
  • 也可以用線段樹合併維護顏色集合,時間複雜度 O ( N L o g N + 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;
}