题目链接 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;
}