题目: 传送门
思路: 因为选拔赛做过一道类似的题,所以直接就想到并查集了,不得不说这很巧妙。
对于题目给的每条线路,如果为 1 就不并 , 为 0 就 将二者合并 , 这样最后会的到几个集合,如果要从一个集合的某点到另一个集合的某点,则一定会经过 1 的道路。 反过来 ,集合内的点到集合内的点是不会经过含有 1 的道路的,所以我们只要用所有走法减去这样的走法就可以了。
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
const long long mods=1e9+7;
map<int,long long> s;
std::vector<int> v;
int f[200050];
int vis[200050];
int finds(int x) {
return x==f[x]?x:f[x]=finds(f[x]);
}
void unions(int x,int y) {
x= finds(x);
y= finds(y);
if(x==y) return ;
else f[x] =y;
}
long long fastX(long long k,long long x) { //快速幂
long long res = 1;
while(k!=0) {
if(k&1) {
k--;
res=res * x %mods;
}
k>>=1;
x=x*x%mods;
}
return res;
}
int main() {
long long n,k;
cin>>n>>k;
long long ans = fastX(k,n);
for(int i=0;i<=n;i++) f[i]=i;
for(int i=1;i<n;i++) {
int l,r,v;
cin>>l>>r>>v;
if(v==1) continue;
else unions(l,r);
}
for(int i=1;i<=n;i++) {
s[finds(i)] ++;
v.push_back(f[i]);
}
for(int i=0;i<v.size();i++) {
if(vis[v[i]]==1) continue;
ans = (ans - fastX(k,s[v[i]])+mods)%mods;
vis[v[i]] = 1;
}
cout<<ans<<endl;
return 0;
}