题目大意
有一张有nnn个点mmm条边的无向带权图GGG,小艾将它放到一个万花筒中观察。在万花筒中,对于每条边(u,v,w)∈G(u,v,w)\in G(u,v,w)∈G,会在HHH中生成全体((u+1) mod +1,(v+i) mod n+1,w)((u+1)\bmod+1,(v+i)\bmod n+1,w)((u+1)mod+1,(v+i)modn+1,w)的边,最后的图HHH就是在万花筒中看到的图。
求这个图HHH的最小生成树的权值和,保证生成树存在。
有TTT组数据。
1≤T≤100,1≤n,w≤109,∑m≤1051\leq T\leq 100,1\leq n,w\leq 10^9,\sum m\leq 10^51≤T≤100,1≤n,w≤109,∑m≤105
题解
对于GGG中的每一条边(u,v,w)(u,v,w)(u,v,w),令k=(u−v+n)%nk=(u-v+n)\% nk=(u−v+n)%n,则在HHH中,任意两个满足(i−j+n)%n=k(i-j+n)\% n=k(i−j+n)%n=k的两个点i,ji,ji,j都有一条权值为www的边。那么,对于GGG中的每一条边(u,v,w)(u,v,w)(u,v,w),我们记其对应的HHH中的边集为T(k,w)T(k,w)T(k,w)。
利用Kruskal\text{Kruskal}Kruskal算法的思想,我们将这些边集按www从小到大排序,并依次遍历以构建最小生成树。
设当前的nnn个点中没有任何两个点有连边,当前枚举到的边集为T(k,w)T(k,w)T(k,w),则将nnn中所有满足(i−j+n)%n=k(i-j+n)\% n=k(i−j+n)%n=k且不在同一个连通块的两个点i,ji,ji,j连一条边。那么,这nnn个点就会分为d=gcd(n,k)d=\gcd(n,k)d=gcd(n,k)个连通块,且同一个连通块中的点的编号模ddd后的值一定相等(可以自己举几个例子试一下)。
这样的话,这个图就连上了n−dn-dn−d条边,边集T(k,w)T(k,w)T(k,w)对答案的贡献为(n−d)×w(n-d)\times w(n−d)×w。
再考虑下一组边集T(k′,w′)T(k',w')T(k′,w′),类似地,将nnn中所有满足(i−j+n)%n=k′(i-j+n)\% n=k'(i−j+n)%n=k′且不在同一个连通块的两个点i,ji,ji,j连一条边。这时,我们发现,iii所在的连通块中的点模ddd后的值均为i%di\%di%d,jjj所在的连通块中的点模ddd后的值均为j%dj\% dj%d,那么我们可以将iii和jjj连边看作i%di\% di%d和j%dj\% dj%d连边(i%di\% di%d或j%dj\% dj%d的值为000时将其值看作ddd),这样显然是等价的。
换句话说,我们将每个连通块都看成了一个点,而这个点表示的连通块就是一棵树。
那么,在连完T(k,w)T(k,w)T(k,w)的边之后,问题可以看作剩下ddd个点且其中没有任何两个点有连边,要求其在连上剩下的边集后的最小生成树的权值和。
每次多加一个边集,就按上面所说的操作一次,并算上边的贡献。因为保证生成树存在,所以最终一定只剩下一个点,而这一个点所表示的连通块就是图HHH的最小生成树。
将每次操作的贡献求和,即可得到答案。
时间复杂度为O(m)O(m)O(m)。
code
#include<bits/stdc++.h>
using namespace std;
int T,n,m,now,d;
long long ans;
struct node{
int t,w;
}v[100005];
bool cmp(node ax,node bx){
return ax.w<bx.w;
}
int gcd(int i,int j){
while(j){
i%=j;swap(i,j);
}
return i;
}
int main()
{
freopen("kaleidoscope.in","r",stdin);
freopen("kaleidoscope.out","w",stdout);
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
v[i].t=(x-y+n)%n;
v[i].w=z;
}
sort(v+1,v+m+1,cmp);
now=n;
ans=0;
for(int i=1;i<=m;i++){
d=gcd(now,v[i].t%now);
ans+=1ll*(now-d)*v[i].w;
now=d;
}
printf("%lld\n",ans);
}
return 0;
}
文章讨论了如何在一张有n个点和m条边的无向带权图中,通过观察其在万花筒中的变换规则,求解生成树的权值和。利用Kruskal算法和连通块的概念,通过计算每个边集的贡献,得出最小生成树的总权值。时间复杂度为O(m)。

被折叠的 条评论
为什么被折叠?



