题目链接:
题目大意:
给你一棵树(一个没有循环的连通无向图) ñ顶点。每一个n - 1 树的边缘用黑色或红色着色。
你也给了一个整数 k,考虑序列k顶点。我们叫一个序列[ a1,a2,… ,aķ] 如果它满足以下标准则很好:
我们将从树上开始走路径(可能多次访问相同的边/顶点) 开始于a1 结束于 ak。每次都走最短路径
如果你在这个过程中至少走过一条黑色边缘,那么顺序是好的。
k=3时,[1,4,7], [5,5,3] and [2,3,7]是好的。 [1,4,6], [5,5,5], [3,7,3]不是好的。
问你好的序列数量,mod(1e9+7)
思路:当时一直从正面考虑,满足的个数。无法容斥。只要从反面考虑。所有可能的-不满足的。
两点的路径没有经过黑色边,那么他们就在一个连通块内。
答案就是:
p:每个连通块的点数量。
求连通块:dfs起点不经过黑边,能访问到的所有点就是一个连通块。每次得到一个连通块直接快速幂就行了。
注意:因为都是mod过后的,得到的答案可能为负。因为答案一定是正数,所以自己每次调整一下。
ans=(ans+mod)%mod
#include<bits/stdc++.h>
typedef long long LL;
#define p1 first
#define p2 second
using namespace std;
const int mod=1e9+7;
//memset(a, 0, sizeof(a));
//stack堆栈 queue队列 priority_queue优先队列
//vector向量 multiset平衡二叉树 deque双端队列
//pair{T1 first;T2 second;} greater<T>
//unordered_map 哈希map
vector<pair<int, int> > v[200005];
int vis[200005];
LL cut=0;
//快速乘法(a*b)%mod
LL quick_mul(LL a, LL b)
{
LL ans=0;
while(b)
{
if(b&1)
ans=(ans+a)%mod;
a=(a+a)%mod;
b>>=1;
}
return ans;
}
//快速幂(a^b)%mod
LL quick_pow(LL a, LL b)
{
LL ans=1;
while(b)
{
if(b&1)
ans=quick_mul(ans, a);
a=quick_mul(a, a);
b>>=1;
}
return ans;
}
int dfs(int u)
{
vis[u]=1;
cut++;
for(int i=0;i<v[u].size();i++)
{
int t=v[u][i].p1;
if(!vis[t]&&!v[u][i].p2)
{
dfs(t);
}
}
}
int main()
{
LL n, k;
cin>>n>>k;
for(int i=0;i<n-1;i++)
{
int u, t, w;
scanf("%d%d%d",&u,&t,&w);
v[u].push_back({t, w});
v[t].push_back({u, w});
}
memset(vis, 0, sizeof(vis));
LL ans=quick_pow(n, k);
for(int i=1;i<=n;i++)
{
cut=0;
if(!vis[i])
{
dfs(i);
}
ans-=quick_pow(cut, k);
ans=(ans+mod)%mod;
}
cout<<ans<<endl;
return 0;
}