Codeforces 1139C

看似很难,实则很简单的一道题,把样例推出来就想明白了。
首先从正面肯定不好搞,故反面求之,若一条边的color是0,可知k位可以从该边连接的两点任选,,减去2^ k。同理,若由三个点两两相连的边都是0,那么从3个点人选,即3^k。
想到了什么??
对,就是并查集!
最后,对一个点,若与之相连的所有边都是1,就要减1,也就是1^k。

#include<bits/stdc++.h>
using namespace std;
#define forn(i,n) for(int i = 0;i<int(n);i++)
typedef long long LL;
const LL mod = 1e9 + 7;
LL n,k,ans,u,v,w,cnt;
int fa[202020],num[202020];
bool is[202020];
LL fastmuti(LL a,LL b){
	LL ans = 0;
	while(b){
		if(b & 1) ans = (ans + a) % mod;
		a = (a + a) % mod;
		b >>=1 ;
	}
	return ans; 
}
LL fastmi(LL a,LL n){
	LL ans = 1;
	while(n){
		if(n&1) ans = fastmuti(ans,a);
		a = fastmuti(a,a);
		n>>=1;
	} 
	return ans;
}
int find(int x){
	return x ==fa[x] ? x : fa[x] = find(fa[x]);
}
void Union(int u,int v){
	u = find(u);v = find(v);
	fa[u] = v;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	//freopen("data.in","r",stdin);
	//freopen("data.out","w",stdout);
	//cout<<fastmi(1,5)<<endl; 
	cin>>n>>k;
	for(int i = 1;i<=n;i++) fa[i] = i;
	for(int i = 1;i<n;i++){
		cin>>u>>v>>w;
		if(!w) {
			is[u] = is[v] =1 ;
			Union(u,v); 
		} 
	}
	for(int i = 1;i<=n;i++)
		if(is[i]) cnt++;
	ans = fastmi(n,k);
	for(int i = 1;i<=n;i++)
		num[find(i)]++;
	for(int i = 1;i<=n;i++){
		if(num[i]) ans -= fastmi(num[i],k);
		ans = (ans + mod ) %mod;
	}
	cout<<(ans + mod) % mod; 
	return 0; 
} 

猜你喜欢

转载自blog.csdn.net/winhcc/article/details/88739753