HDU 6251 Inkopolis(2017 CCPC-Final,I题,环套树 + 结论)

题目链接 HDU 6251

题意 给出一个$N$个点$N$条边的无向图。然后给出$M$个操作,每个操作为$(x, y, z)$,表示把连接

$x$和$y$的边的颜色改成$z$。

求这张无向图中所有边的颜色的连通块数量。

 

首先不难得到这是一个环套树的结构。

首先考虑一棵树的情形。

设$f[i]$为$i$这个结点的所有边中的不同颜色数目。

那么整棵树的所有边的颜色的连通块数量即为$∑f(i) - (n - 1)$

 

现在把这个结论推广到环套树上。

设$f[i]$为$i$这个结点的所有边中的不同颜色数目。

那么整个图的所有边的颜色的连通块数量即为$∑f(i) - n$

但是有一种特殊情况,若这个环上所有的边的颜色相同

那么整个图的所有边的颜色的连通块数量为$∑f(i) - (n - 1)$

 

#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)
#define	MP		make_pair
#define	fi		first
#define	se		second

typedef pair <int, int> PII;

const int N = 2e5 + 10;

unordered_map <int, int> mp[N], cp;
map <PII, int> mp2;
map <PII, int> oncircle;

vector <int> v[N];
int T;
int n, m, cnt;
int isroot[N];
int a[N], vis[N];
int father[N];
int f[N];
int ans;
int cir;
int ca = 0;


int getcircle(int x){
	vis[x] = 1;
	for (auto u : v[x]){
		if (u == father[x]) continue;
		father[u] = x;
		if (vis[u]){
			cnt = 0;
			int w = x;
			while (w ^ u){
				a[++cnt] = w;
				isroot[w] = cnt;
				w = father[w];
			}

			a[++cnt] = u;
			isroot[u] = cnt;
			return 1;
		}

		if (getcircle(u)) return 1;
	}

	return 0;
}

int main(){

	scanf("%d", &T);
	while (T--){
		printf("Case #%d:\n", ++ca);
		scanf("%d%d", &n, &m);
		rep(i, 0, n + 1) v[i].clear();
		rep(i, 0, n + 1) mp[i].clear();
		mp2.clear();
		oncircle.clear();
		cp.clear();
		cnt = 0;
		rep(i, 0, n + 1) a[i] = 0;
		rep(i, 0, n + 1) f[i] = 0;
		ans = 0;
		cir = 0;
		rep(i, 1, n){
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			if (x > y) swap(x, y);
			v[x].push_back(y);
			v[y].push_back(x);
			if (mp[x][z] == 0){
				++f[x];
				++mp[x][z];
			}

			else ++mp[x][z];
			if (mp[y][z] == 0){
				++f[y];
				++mp[y][z];
			}

			else ++mp[y][z];
			mp2[MP(x, y)] = z;
		}

		rep(i, 1, n) ans += f[i];

		rep(i, 0, n + 1) vis[i] = 0;
		getcircle(1);

		a[++cnt] = a[1];
		rep(i, 1, cnt - 1){
			int x = a[i], y = a[i + 1];
			if (x > y) swap(x, y);
			oncircle[MP(x, y)] = 1;
		}

		for (auto u : oncircle){
			int tt = mp2[MP(u.fi.fi, u.fi.se)];
			if (cp[tt] == 0){
				++cir;
				++cp[tt];
			}

			else ++cp[tt];
		}

		while (m--){
			int x, y, z;
			scanf("%d%d%d", &x, &y, &z);
			if (x > y) swap(x, y);
			int old = mp2[MP(x, y)];
			--mp[x][old];
			if (mp[x][old] == 0) --f[x], --ans;
			--mp[y][old];
			if (mp[y][old] == 0) --f[y], --ans;


			if (oncircle.count(MP(x, y)) > 0){
				--cp[old];
				if (cp[old] == 0) --cir;
			}


			mp2[MP(x, y)] = z;
			if (mp[x][z] == 0){
				++mp[x][z];
				++f[x];
				++ans;
			}

			else ++mp[x][z];


			if (mp[y][z] == 0){
				++mp[y][z];
				++f[y];
				++ans;
			}

			else ++mp[y][z];

			if (oncircle.count(MP(x, y)) > 0){
				if (cp[z] == 0){
					++cp[z];
					++cir;
				}

				else ++cp[z];
			}

			if (cir == 1) printf("%d\n", ans - n + 1);
			else printf("%d\n", ans - n);            
		}
	}

	return 0;
}

 

posted @ 2018-01-06 22:28  cxhscst2  阅读(532)  评论(0编辑  收藏  举报