UVALive 7638

来源:互联网 发布:巫师3狼派装备数据 编辑:程序博客网 时间:2024/06/08 00:15

题目大意:两个结点之间的gcd>1,那么这两个结点就可以建边,问最终有几个联通块。

题目思路:想到了并查集,但是单纯使用就T掉了O(n^2)。看了网上别的大神的博客,大体思路是这样的:把每个数进行质因数分解,然后把这个数和他的质因数建边。那么只要有相同质因数的两个数都会在同一个联通块里,因为x1<=1e6,那么遍历1~1e6的所有数字,该有边的肯定会在一个联通块里面O(n)。(比赛时候没想到,下回注意,放在这里提醒自己)。

代码如下:

<textarea readonly="readonly" name="code" class="c++"> 

#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <string>
#include <vector>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxm=1000005;
int n,a[maxm];
int par[maxm],rak[maxm];
bool vis[maxm];
int ans;
vector<int> g[maxm];
void inite()
{
for(int i=1;i<=maxm;i++)
{
par[i]=i;
rak[i]=0;
}
}
int find(int x)
{
if(par[x]==x) return x;
else {
return par[x]=find(par[x]);
}
}
void unite(int x,int y)
{
x=find(x);
y=find(y);
if(x==y) return;
if(rak[x]<rak[y]){
par[x]=y;
}
else{
par[y]=x;
if(rak[x]==rak[y]) rak[x]++;
}
}
void solve()
{
for(int i=2;i<=maxm;i++)
for(int j=i;j<=maxm;j+=i)
g[j].push_back(i);
}//把数和质因数建边啊。
int main()
{
solve();//o(n)复杂度。
int t,kase=1;
scanf("%d",&t);
while(t--)
{   
inite();
ans=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
for(int j=0;j<g[a[i]].size();j++)
unite(a[i],g[a[i]][j]);
}
memset(vis,false,sizeof(vis));
for(int i=0;i<n;i++)
{
int f=find(a[i]);
if(!vis[f])
{
ans++;
if(a[i]!=1) 
vis[f]=true;
}

printf("Case %d: %d\n",kase++,ans);
}
return 0;
}

</textarea>


原创粉丝点击