Codeforces990 G. GCD Counting(点分治)
Posted live4m
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces990 G. GCD Counting(点分治)相关的知识,希望对你有一定的参考价值。
题意:
解法:
点分治.
对于点x,用map维护子树点到x的数的个数,
每次暴力计算经过x的路径即可,
由于gcd是收敛的,数不会太多.
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxm=2e5+5;
int head[maxm],nt[maxm<<1],to[maxm<<1],tot;
int sz[maxm],son[maxm],root,size;
int mark[maxm];
ll cnt[maxm];
int a[maxm];
int n;
void add(int x,int y){
tot++;nt[tot]=head[x];head[x]=tot;to[tot]=y;
}
void getroot(int x,int fa){
sz[x]=1;son[x]=0;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(v==fa||mark[v])continue;
getroot(v,x);
sz[x]+=sz[v];
son[x]=max(son[x],sz[v]);
}
son[x]=max(son[x],size-sz[x]);
if(son[x]<son[root])root=x;
}
map<int,int>last;
map<int,int>now;
void dfs(int x,int fa,int val){
now[val]++;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(v==fa||mark[v])continue;
dfs(v,x,__gcd(val,a[v]));
}
}
void solve(int x){
cnt[a[x]]++;
last.clear();
last[a[x]]++;
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(mark[v])continue;
now.clear();
dfs(v,x,__gcd(a[x],a[v]));
for(auto i:now){
for(auto j:last){
cnt[__gcd(i.first,j.first)]+=1ll*i.second*j.second;
}
}
for(auto i:now){
last[i.first]+=i.second;
}
}
}
void divide(int x){
mark[x]=1;
solve(x);
for(int i=head[x];i;i=nt[i]){
int v=to[i];
if(mark[v])continue;
son[root=0]=size=sz[v];
getroot(v,v);
divide(root);
}
}
void solve(){
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<n;i++){
int a,b;scanf("%d%d",&a,&b);
add(a,b);add(b,a);
}
son[root=0]=size=n;
getroot(1,1);
divide(root);
for(int i=1;i<=2e5;i++){
if(cnt[i]){
printf("%d %lld\\n",i,cnt[i]);
}
}
}
signed main(){
solve();
return 0;
}
以上是关于Codeforces990 G. GCD Counting(点分治)的主要内容,如果未能解决你的问题,请参考以下文章
Educational Codeforces Round 36 (Rated for Div. 2) G. Coprime Arrays
Codeforces915 G. Coprime Arrays(莫比乌斯容斥,差分前缀和优化)
Educational Codeforces Round 48 (Rated for Div. 2)G. Appropriate Team
2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (线段树+GCD)