E. Kamil and Making a Stream
题意:
输入
n
(
1
e
5
)
n(1e5)
n(1e5),表示树有
n
n
n个节点;
输入
x
1
,
x
2
,
…
,
x
n
(
1
e
12
)
x_1,x_2,\dots,x_n(1e12)
x1,x2,…,xn(1e12)表示树上节点的权值;
接下来
n
−
1
n-1
n−1行每行输入
u
,
v
u,v
u,v表示树边。
问树中所有存在父子关系的点对,求两点路径权值的
g
c
d
gcd
gcd,求出所有点对
g
c
d
gcd
gcd和。
题解1(树上倍增):
1、首先预处理出倍增数组:
f
[
u
]
[
i
]
f[u][i]
f[u][i]表示从
u
u
u开始向上
2
i
2^i
2i的节点是什么。
g
g
[
u
]
[
i
]
gg[u][i]
gg[u][i]表示从
u
u
u开始向上
2
i
2^i
2i的节点及经过节点权值最大公约数。
2、然后对每个点算它作为子孙的贡献:
那么就应该找的祖先节点。
向上倍增的找相同
g
c
d
gcd
gcd的一段,然后继续向上,直到根节点。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+9;
#define ll long long
const int mod=1e9+7;
ll x[N],n;
vector<int>g[N];
inline ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
ll f[N][21],gg[N][21],dep[N];
void dfs(int u,int fa){
gg[u][0]=gcd(x[u],x[fa]);f[u][0]=fa;dep[u]=dep[fa]+1;
for(int i=1;i<=20;i++)f[u][i]=f[f[u][i-1]][i-1],gg[u][i]=gcd(gg[u][i-1],gg[f[u][i-1]][i-1]);
for(auto v:g[u]){
if(v==fa)continue;
dfs(v,u);
}
}
ll ans;
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)cin>>x[i];
for(int i=1,u,v;i<n;i++)cin>>u>>v,g[u].push_back(v),g[v].push_back(u);
dfs(1,0);
for(int i=1;i<=n;i++){
ll gys=x[i],l=i,r=i;
while(r){
for(int j=20;j>=0;j--)if(gcd(gys,gg[l][j])==gys&&f[l][j])l=f[l][j];
ans=(ans+1ll*gys*(dep[r]-dep[l]+1))%mod;
l=r=f[l][0],gys=gcd(gys,x[r]);
}
}
cout<<ans<<endl;
return 0;
}
题解2(无脑dfs暴力)
虽说是无脑暴力,但它跑起来比树上倍增要快。一开始我从底向上合并
g
c
d
gcd
gcd,直到根节点,这样会超时;后来灵机一动,直接从顶向下传递
g
c
d
gcd
gcd就好了,这样就变成一条链的
g
c
d
gcd
gcd,显然不会TLE。
每个节点维护的是从根节点到该节点的后缀
g
c
d
gcd
gcd,可以用
m
a
p
,
v
e
c
t
o
r
map,vector
map,vector等维护。
代码:
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define ll long long
#define mp map<ll,int>
using namespace std;
const int mod=1e9+7;
const int N=1e5+9;
ll x[N],n;
mp y[N];
vector<int>g[N];
ll ans=0;
inline ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
void dfs(int u,int fa){
y[u][x[u]]++;
for(auto i:y[fa])y[u][gcd(x[u],i.first)]+=i.second;
for(auto v:g[u]){
if(v==fa)continue;
dfs(v,u);
}
for(auto j:y[u])ans=(ans+j.first%mod*j.second)%mod;
y[u].clear();
}
int main(){
// freopen("tt.in","r",stdin),freopen("tt.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++)cin>>x[i];
for(int i=1,u,v;i<n;i++)cin>>u>>v,g[u].push_back(v),g[v].push_back(u);
dfs(1,0);
// for(int i=1;i<=n;i++){
// for(auto j:y[i])cout<<j.first<<" "<<j.second<<endl;
// }
cout<<ans<<endl;
return 0;
}