题意:给你一颗带有点权的树,求:(所有点权值不一样,且对于任意 i :ai<=n,这点十分重要)
思路:根据欧拉函数的性质推一下:
先不管前面的n,设ans:
枚举gcd:
设 F(x):
莫比乌斯反演:
假设我们已经求好所有的F(x),那么我们可以两层for循环求出答案,因为现在这个式子的复杂度是调和级数。
我们发现影响F(x)的点的权值全都是 x 的倍数,那么我们可以把这些点取出来建虚树,但是对于任意的x,我们都要建虚树,不难证明,所有虚树的总大小为调和级数,复杂度ok,那么建好虚树后怎么树形dp?
设:dp[u]为u子树中所有点的欧拉函数 * u到该点的距离和,sum[u]为u子树欧拉函数的总和,d为点u的权值。
由儿子 v 到 u 的转移方程:dp[u]+=dp[v]+w*sum[v] (w为u v的距离)
很显然点 u 的贡献为:phi[d[u]]*dp[u],然后进行换根dp,转移方程很简单不多说。
#include<bits/stdc++.h>
#define pi pair<int,int>
#define mk make_pair
#define ll long long
using namespace std;
const int maxn=2e5+10,mod=1e9+7;
int dep[maxn],f[maxn],top[maxn],id[maxn],sz[maxn],son[maxn],Cnt;
int a[maxn],b[maxn],c[maxn],d[maxn],s[maxn],dp[maxn],sum[maxn],n,Top;
int cnt,pri[maxn],phi[maxn],vis[maxn],F[maxn],mu[maxn];
vector<pi>G[maxn],G2[maxn];
void init()
{
ll res=1;
phi[1]=mu[1]=1;
for(int i=2;i<=n;i++)
{
if(!vis[i])
pri[++cnt]=i,phi[i]=i-1,mu[i]=-1;
for(int j=1;j<=cnt&&pri[j]*i<=n;j++)
{
vis[pri[j]*i]=1;
if(i%pri[j])
phi[i*pri[j]]=phi[i]*phi[pri[j]],mu[i*pri[j]]=-mu[i];
else
{
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
}
}
}
ll ksm(ll x,int y)
{
ll res=1;
while(y)
{
if(y&1)
res=res*x%mod;
x=x*x%mod;
y/=2;
}
return res;
}
void add(int &x,int y)
{
x=x-mod+y;
while(x<0)
x+=mod;
}
void dfs1(int u,int fa,int deep)
{
dep[u]=deep;
f[u]=fa;
sz[u]=1;
for(auto tmp : G[u]){
int v=tmp.first;
if(v==fa)
continue;
dfs1(v,u,deep+1);
sz[u]+=sz[v];
if(sz[son[u]]<sz[v])
son[u]=v;
}
}
void dfs2(int u,int rt)
{
top[u]=rt;
id[u]=++Cnt;
if(son[u])
dfs2(son[u],rt);
for(auto tmp : G[u]) {
int v=tmp.first;
if(v!=f[u]&&v!=son[u])
dfs2(v,v);
}
}
int LCA(int x,int y)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])
swap(x,y);
x=f[top[x]];
}
if(dep[x]>dep[y])
swap(x,y);
return x;
}
bool cmp(int x,int y)
{
return id[x]<id[y];
}
void Add(int x,int y)
{
int z=abs(dep[x]-dep[y]);
G2[x].push_back(mk(y,z));
G2[y].push_back(mk(x,z));
}
void insert(int x)
{
if(Top==1)
{
s[++Top]=x;
return;
}
int lca=LCA(x,s[Top]);
if(lca==s[Top])
{
s[++Top]=x;
return;
}
while(Top>1&&id[s[Top-1]]>=id[lca])
Add(s[Top-1],s[Top]),Top--;
if(lca!=s[Top])
Add(lca,s[Top]),s[Top]=lca,d[lca]=0;
s[++Top]=x;
}
void dfs3(int u,int fa)
{
dp[u]=0;
sum[u]=phi[d[u]];
for(auto tmp : G2[u]) {
if(tmp.first==fa)
continue;
dfs3(tmp.first,u);
add(sum[u],sum[tmp.first]);
add(dp[u],(dp[tmp.first]+1ll*tmp.second*sum[tmp.first]%mod)%mod);
}
}
void dfs4(int &ans,int u,int fa)
{
add(ans,1ll*phi[d[u]]*dp[u]%mod);
for(auto tmp : G2[u]) {
int v=tmp.first,w=tmp.second;
if(v==fa)
continue;
int temp=dp[u],temp2=(dp[v]+1ll*w*sum[v]%mod)%mod;
add(temp,mod-temp2);
add(dp[v],(temp+1ll*w*(sum[u]-sum[v]+mod)%mod)%mod);
sum[v]=sum[u];
dfs4(ans,v,u);
}
G2[u].clear();
}
int main()
{
int u,v,ans=0;
scanf("%d",&n);
init();
for(int i=1;i<=n;i++)
scanf("%d",&a[i]),b[a[i]]=i;
for(int i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
G[u].push_back(mk(v,1));
G[v].push_back(mk(u,1));
}
dfs1(1,0,1);
dfs2(1,1);
for(int i=1;i<=n;i++)
{
int cur=0;
for(int j=i;j<=n;j+=i)
c[++cur]=b[j],d[b[j]]=j;
sort(c+1,c+1+cur,cmp);
s[Top=1]=0;
for(int i=1;i<=cur;i++)
insert(c[i]);
while(Top>1)
Add(s[Top-1],s[Top]),Top--;
dfs3(0,0);
dfs4(F[i],0,0);
}
for(int i=1;i<=n;i++)
{
int res=0;
for(int j=i;j<=n;j+=i)
add(res,mu[j/i]*F[j]);
add(ans,1ll*i*ksm(phi[i],mod-2)%mod*res%mod);
}
ans=1ll*ans*ksm(1ll*n*(n-1)%mod,mod-2)%mod;
printf("%d\n",ans);
}