题目链接:
题目大意:
给你一棵树(一个没有循环的连通无向图) ñ顶点。每一个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;
}