https://codeforces.com/contest/1230/problem/E
题意:给定一棵树,树上每一个点都有一个点权,root=1。定义f(u,v)为u到v路径上所有点的点权的gcd(u为v的祖先)。让你求所有的f(i,j)之和。
解法:暴力,直接dfs。用map存储当前点到所有祖先节点可能的gcd值,和gcd值出现的次数。不会t吗?不会!假设x为当前访问的结点,y为x的祖先,z为y的祖先。那么f(y,x)>=f(z,x),并且f(z,x)一定是f(y,x)的因子。所以对于当前点x,它到祖先的的因子一定是a[x]的因子,a[x]<=1e12。所以因子的个数最多是log2(1e12)。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
const ll mod=1e9+7;
ll a[maxn];
vector<int> v[maxn];
map<ll,int> Map[maxn];
map<ll,int>::iterator it;
ll ans=0;
ll gcd(ll x,ll y){
if(0==y) return x;
return gcd(y,x%y);
}
void dfs(int x,int fa){
Map[x][a[x]]=1;
for(it=Map[fa].begin();it!=Map[fa].end();it++){
Map[x][gcd(it->first,a[x])]+=it->second;
}
for(it=Map[x].begin();it!=Map[x].end();it++){
ans+=it->first*it->second;
ans%=mod;
}
for(int i=0;i<v[x].size();i++){
int y=v[x][i];
if(y==fa) continue;
dfs(y,x);
}
}
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
for(int i=0,a,b;i<n-1;i++){
scanf("%d%d",&a,&b);
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1,0);
printf("%lld\n",ans%mod);
return 0;
}