1. 程式人生 > >省選專練之GCD生成樹

省選專練之GCD生成樹

非常著名的一道經典題。

考慮一個性質:如果兩個點GCD相同必然更優。

於是我們有了一些點權互不相同的點。

發現點權並不大,從大到小列舉點權。

用並查集維護聯通性。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
inline void read(int &x){
    x=0;
    int f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
const int N=1e6+10;
int T[N];
int fa[N];
inline int getfa(int x){
	if(fa[x]==x)return x;
	else return fa[x]=getfa(fa[x]);
}
int n;
int val[N];
int Mx;
int ans=0;
int main(){
	read(n);
	for(int i=1;i<=n;++i){
		read(val[i]);
		Mx=max(Mx,val[i]);
		if(T[val[i]])ans+=val[i];
		else T[val[i]]=fa[i]=i;
	}
	for(int i=Mx;i>=1;--i){
		int now=0;
		for(int j=1;j*i<=Mx;++j){
			if(T[i*j]){
				if(!now)now=T[i*j];
				else{
					if(getfa(now)==getfa(T[i*j]))continue;
					else{
						fa[getfa(now)]=getfa(T[i*j]);
						ans+=i;
					}
				}
			}
		}
	}
	cout<<ans;
}