G. Counting Graphs(并查集)

Problem - G - Codeforces

G. Counting Graphs(并查集)_第1张图片

给定一个由n个顶点组成的树。树是一个无圈的连通无向图。树的每条边都有它的权重wi。

你的任务是计算满足以下四个条件的不同图形的数量:

 
  

Plain Text

 
  
图形没有自环和多重边。
图形的边上的权重是整数且不超过S。

图形只有一个最小生成树。
图形的最小生成树是给定的树。

如果两个图的边集不同,则被认为是不同的,考虑到边的权重。

答案可能很大,对998244353取模后输出。

输入:

第一行包含一个整数t(1≤t≤104),表示测试用例的数量。

每个测试用例的第一行包含两个整数n和S(2≤n≤2⋅105,1≤S≤109),表示顶点的数量和权重的上界。

接下来的n-1行描述了树的边,第i行包含三个整数ui,vi和wi(1≤ui,vi≤n,ui≠vi,1≤wi≤S),表示一条权重为wi的边。

保证所有测试用例中n的总和不超过2⋅105。

输出:

对每个测试用例,输出满足条件的不同图形的数量,对998244353取模后输出。

Example

Input

Copy

 
  

4

2 5

1 2 4

4 5

1 2 2

2 3 4

3 4 3

5 6

1 2 3

1 3 2

3 4 6

3 5 1

10 200

1 2 3

2 3 33

3 4 200

1 5 132

5 6 1

5 7 29

7 8 187

7 9 20

7 10 4

Output

Copy

1
8
80
650867886

题解:
既然是最小生成树,想想与最小生成树有关的算法,kruskal利用并查集,每次链接两个不在一个集合里面的点,最终使得整个图联通

假设我们现在有两个未在一个集合的集合s1,s2,最多需要s1*s2 - 1条边链接,为啥减一,因为不能有重边,这些边的取值范围x是多少,应该是w < x <= s

每条边有s - w种情况,但是我们也可以啥也不连,所以加一种情况为s - w + 1

每条边都可以这样

情况数为,(s - w + 1)^(s1*s2 - 1)种情况,每次链接两个不相连的集合,都会是这样,所以相乘

#include
using namespace std;
#define int long long
struct node
{
	int x,y,w;
}a[200040];
bool cmp(node a,node b)
{
	return a.w < b.w;
}
int f[200040],d[200043];
int find(int x)
{
	if(f[x] == x)
	return f[x];
	return f[x] = find(f[x]);
}
int mod = 998244353;
int qpow(int x,int p)
{
	int ans = 1;
	while(p)
	{
		if(p&1)
		ans = ans*x%mod;
		x = x*x%mod;
		p /= 2;
	}
	return ans;
}
void solve()
{
	int n,s;
	cin >> n >> s;
	for(int i = 1;i < n;i++)
	{
		int x,y,w;
		cin >> x >> y >> w;
		a[i] = {x,y,w};
	}
	for(int i = 1;i <= n;i++)
	{
		f[i] = i;
		d[i] = 1;
	}
	sort(a + 1,a + n,cmp);
	int ans = 1;
	for(int i = 1;i < n;i++)
	{
		int x = find(a[i].x);
		int y = find(a[i].y);
		ans = ans*qpow(s - a[i].w + 1,d[x]*d[y] - 1)%mod;
		f[y] = x;
		d[x] += d[y];
	}
	cout << ans <<"\n";
}
signed main()
{
	int t = 1;
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> t;
	while(t--)
	{
		solve();
	}
}

你可能感兴趣的:(并查集)