cf 990G GCD Counting (莫比烏斯反演 並查集)
阿新 • • 發佈:2018-06-20
In http 自己 har urn merge cto count read 。
990G
給你一棵樹,問你有多少個點對(x,y)(x\(\leq\)y),使得(x,y)簡單路徑上的點權值的\(gcd\)為\(i\),對於\(i\in [1,200000]\)輸出點對數目。
這題沒有做出來,主要還是莫比烏斯反演時間太長不熟悉了。同時統計點對的技巧也自己沒有想出來,實在是不應該。
我們設\(h(i)\)是有多少個點對(x,y)(x\(\leq\)y),使得(x,y)簡單路徑上的點權值的\(gcd\)為\(i\)的倍數的答案。於是有\(h(i)=\sum_{i=1}^{\lfloor maxa/i \rfloor} ans(k\cdot i)\)。即\(ans(i)=\sum_{k=1}^{\lfloor maxa/i \rfloor} h(k\cdot i)\mu(k)\)
於是我們就要統計\(h(i)\)。這個怎麽統計呢,就是要有這樣的簡單路徑存在那肯定是有一整個聯通塊,這個聯通塊裏的點的點權全部是\(i\)的倍數,我們就要找這些聯通塊出來。把所有\(i\)的倍數的點拿出來,並查集合並大小到父親,然後統計所有的父親對答案的貢獻即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
inline int readInt() {
char c; int tmp=0,x=1; c=getchar();
while(c>‘9‘ || c<‘0‘) {if (c==‘-‘) x=-1; c=getchar();}
while(c>=‘0‘ && c<=‘9‘) {tmp=tmp*10+c-‘0‘; c=getchar();}
return tmp*x;
}
const int maxN=200000+10;
int a[maxN],n;
vector<int > g[maxN];
void addEdge(int u,int v) {
g[u].push_back(v); g[v].push_back(u);
}
bool vis[maxN];
int pri[maxN],tot=0,mu[maxN];
void sieve() {
mu[1]=1;
for(int i=2;i<maxN;i++) {
if(!vis[i]) pri[++tot]=i,mu[i]=-1;
for(int j=1;j<=tot && pri[j]*i<maxN;j++) {
vis[pri[j]*i]=true;
if(i%pri[j]==0) {
mu[pri[j]*i]=0;
break;
}
mu[pri[j]*i]=-mu[i];
}
}
}
int Fa[maxN];
void dfs(int v,int fa) {
Fa[v]=fa;
for(int i=0;i<(int)g[v].size();i++) {
int u=g[v][i];
if(u!=fa) dfs(u,v);
}
}
int siz[maxN],f[maxN];
int getFather(int x) {
return x==f[x]?f[x]:f[x]=getFather(f[x]);
}
void mergeUnion(int u,int v) {
int fu=getFather(u),fv=getFather(v);
if(fu==fv) return;
else {
if(siz[fu]>siz[fv]) swap(fu,fv);
siz[fv]+=siz[fu];
f[fu]=fv;
}
}
vector<int > hav[maxN],all;
ll h[maxN],ans[maxN];
int main() {
sieve();
memset(vis,0,sizeof(vis));
n=readInt();
for(int i=1;i<=n;i++) a[i]=readInt(),hav[a[i]].push_back(i);
int u,v;
for(int i=1;i<=n-1;i++) {
u=readInt(),v=readInt();
addEdge(u,v);
}
dfs(1,-1);
for(int i=1;i<=200000;i++) {
for(int k=0;k<(int)all.size();k++) siz[all[k]]=0,f[all[k]]=0,vis[all[k]]=false;
all.clear();
for(int j=i;j<=200000;j+=i) {
for(int k=0;k<(int)hav[j].size();k++) {
siz[hav[j][k]]=1,f[hav[j][k]]=hav[j][k];
all.push_back(hav[j][k]);
}
}
for(int k=0;k<(int)all.size();k++) {
v=all[k];
if(Fa[v]!=-1 && a[Fa[v]]%i==0) mergeUnion(Fa[v],v);
}
for(int k=0;k<(int)all.size();k++) {
v=all[k];
if(!vis[u=getFather(v)]) h[i]+=1ll*siz[u]*(siz[u]+1)/2,vis[u]=true;
}
}
for(int i=1;i<=200000;i++) {
for(int j=1;j<=(200000/i);j++) {
ans[i]+=h[j*i]*1ll*mu[j];
}
}
for(int i=1;i<=200000;i++) {
if(ans[i]>0) printf("%d %I64d\n",i,ans[i]);
}
return 0;
}
cf 990G GCD Counting (莫比烏斯反演 並查集)