正题
题目链接:https://www.luogu.com.cn/problem/P8207
题目大意
有编号为[L,R][L,R][L,R]区间的点,连接两个点x,yx,yx,y边权的为LCM(x,y)LCM(x,y)LCM(x,y),求这张图的最小生成树。
1≤L≤R≤106,R−L≤1051\leq L\leq R\leq 10^6,R-L\leq 10^51≤L≤R≤106,R−L≤105
解题思路
我们有一个结论: 对于张图GGG中的一个生成子图EEE,EEE之中的一条边kkk如果不在EEE最小生成树中,那么kkk肯定也不在GGG的最小生成树中。
那么我们考虑找一些可能是答案的边出来跑最小生成树。
对于一个iii我们提取出所有它倍数的点,对于点ikikik来说它肯定不会去连接某个ik′ik'ik′如果存在另一个更小的ik′′ik''ik′′的话,因为这条边显然不在这张图的最小生成树中。
所以我们可以对于一个点xxx的每个约数ddd,我们只连接一个最小的d×kd\times kd×k,然后把这些边拿出来跑KruskalKruskalKruskal就好了。
时间复杂度:O(nlog2n)O(n\log^2 n)O(nlog2n)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
struct node{ll x,y,w;
}e[11000000];
ll L,R,ans,m,fa[1100000];
bool cmp(node x,node y)
{return x.w<y.w;}
ll find(ll x)
{return (fa[x]==x)?x:(fa[x]=find(fa[x]));}
signed main()
{scanf("%lld%lld",&L,&R);for(ll i=1;i<=R;i++){for(ll j=i;j<=R;j+=i){if(j>=L){ll p=(L+i-1)/i*i;if(p==j)continue;e[++m]=(node){j,p,j*p/i};}}}sort(e+1,e+1+m,cmp);for(ll i=L;i<=R;i++)fa[i]=i;for(ll i=1;i<=m;i++){ll x=find(e[i].x),y=find(e[i].y);if(x==y)continue;ans+=e[i].w;fa[x]=y;}printf("%lld\n",ans);return 0;
}