zoukankan      html  css  js  c++  java
  • 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:
    ", ++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
    ", ans - n + 1);
    			else printf("%d
    ", ans - n);            
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Java当中的IO
    Java当中的类集框架
    Java当中的JVM
    Java当中的常量池
    详细讲解String和StringBuffer和StringBuilder的使用
    Java中流的操作以及编码解码
    VMware-workstation12.5.6 新建虚拟机 安装 centos6.5
    linux 常用命令
    macos 下安装brew
    mysql 的一些事
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/8215564.html
Copyright © 2011-2022 走看看