题意:给一棵n个点,边被红黑染色的树,给定m,有多少种选法,选出可重集满足从走到,再从走到,......,再从走到(都走最短路径),至少经过一条黑边。
题解:由于是最少经过一条黑边,直接算不好算,所以正难则反尝试算有多少种选法使得走下来只经过红边。显然这样选必须在某个只含红边的极大连通子图里选。于是只用并查集连红边,每次合并计算一下贡献即可,类似Codeforces 1213G。记计算出的选法有种,那么。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int N=1e5+4;
int n,m;
struct Edge {
int u,v,c;
}e[N];
int fa[N];
ll siz[N],rev,ans;
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline ll fpow(ll a,ll b) {
ll ret=1;
while (b) {
if (b&1) ret=ret*a%MOD;
b>>=1,a=a*a%MOD;
}
return ret;
}
inline int find(int x) {
return fa[x]==x?fa[x]:fa[x]=find(fa[x]);
}
inline void merge(int u,int v) {
int fu=find(u),fv=find(v);
if (fu^fv) {
fa[fu]=fv;
(rev-=fpow(siz[fu],m))%=MOD;
(rev+=MOD)%=MOD;
(rev-=fpow(siz[fv],m))%=MOD;
(rev+=MOD)%=MOD;
siz[fv]+=siz[fu];
(rev+=fpow(siz[fv],m))%=MOD;
}
}
int main() {
n=read(),m=read();
for (register int i=1;i<n;++i) {
e[i].u=read();
e[i].v=read();
e[i].c=read();
}
for (register int i=1;i<=n;++i) {
fa[i]=i;
siz[i]=1;
++rev;
}
for (register int i=1;i<n;++i) {
if (e[i].c) continue;
merge(e[i].u,e[i].v);
}
ans=(fpow(n,m)-rev)%MOD;
(ans+=MOD)%=MOD;
cout<<ans<<endl;
return 0;
}