# Codeforces 809E：Surprise me! （莫比乌斯反演+虚树）

$ans=\sum _{T=1}^{n}\sum _{d|T}\frac{d\mu \left(\frac{T}{d}\right)}{\varphi \left(d\right)}\sum _{d|{a}_{i}}\sum _{d|{a}_{j}}\varphi \left({a}_{i}\right)\varphi \left({a}_{j}\right)dis\left(i,j\right)$

tail=1;
sak[1]=tree[1];
for (int i=2; i<=Node[d].size(); i++)
{
int x=tree[i],last=0,p=Lca(sak[tail],x);
while ( dep[ sak[tail] ]>dep[p] && tail ) last=sak[tail--];
if (sak[tail]!=p) Fa[p]=sak[tail],sak[++tail]=tree[++cnt]=p;
if (last) Fa[last]=p;
Fa[x]=p;
sak[++tail]=x; //!!!
}
int root=sak[1];
Fa[root]=0;

CODE：

#include<iostream>
#include<string>
#include<cstring>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<stdio.h>
#include<algorithm>
#include<vector>
using namespace std;

const int maxn=200100;
const int maxl=20;
const long long M=1000000007;
typedef long long LL;

struct edge
{
int obj;
edge *Next;
} e[maxn<<1];
int cur=0;

vector <int> Node[maxn];

int Rank[maxn];
int dep[maxn];
int dfn[maxn];
int Time=0;

int Lg[maxn<<1];
int dfsx[maxn<<1];
int ST[maxn<<1][maxl];

int tree[maxn];
int cnt;
int sak[maxn];
int tail;

LL Size[maxn];
int Fa[maxn];

int phi[maxn];
int miu[maxn];

LL rev[maxn];
LL G[maxn];

bool vis[maxn];
int prime[maxn];
int num=0;

int a[maxn];
int n;
LL ans=0;

{
cur++;
e[cur].obj=y;
}

void Linear_shaker()
{
phi[1]=miu[1]=1;
for (int i=2; i<=n; i++)
{
if (!vis[i]) phi[i]=i-1,miu[i]=-1,prime[++num]=i;
for (int j=1; j<=num && i*prime[j]<=n; j++)
{
int k=i*prime[j];
vis[k]=true;
if (i%prime[j])
{
phi[k]=phi[i]*(prime[j]-1);
miu[k]=-miu[i];
}
else
{
phi[k]=phi[i]*prime[j];
miu[k]=0;
break;
}
}
}

rev[1]=1;
for (LL i=2; i<=n; i++)
{
LL x=M/i,y=M%i;
rev[i]=x*rev[y]%M;
rev[i]=M-rev[i];
}

for (int i=1; i<=n; i++) if (miu[i]==-1) miu[i]=M-1;
for (int i=1; i<=n; i++)
for (int j=1; i*j<=n; j++)
G[i*j]=(G[i*j]+ (long long)i*miu[j]%M*rev[ phi[i] ]%M )%M;
}

void Dfs(int node,int fa)
{
dfn[node]=++Time;
dfsx[Time]=node;
{
int son=p->obj;
if (son==fa) continue;
dep[son]=dep[node]+1;
Dfs(son,node);
dfsx[++Time]=node;
}
}

bool Comp(int x,int y)
{
return dfn[x]<dfn[y];
}

int Lca(int x,int y)
{
x=dfn[x],y=dfn[y];
if (x>y) swap(x,y);
int lg=Lg[y-x];
y=y-(1<<lg)+1;
x=ST[x][lg];
y=ST[y][lg];
if (dep[x]<dep[y]) return x;
return y;
}

void Calc(int node)
{
{
int son=p->obj;
Calc(son);
Size[node]=(Size[node]+Size[son])%M;
}
}

int main()
{
freopen("c.in","r",stdin);
freopen("c.out","w",stdout);

scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]),head[i]=NULL;
for (int i=1; i<n; i++)
{
int x,y;
scanf("%d%d",&x,&y);
}

Linear_shaker();

dep[1]=1;
Dfs(1,1);

for (int i=1; i<=Time; i++) ST[i][0]=dfsx[i];
for (int j=1; j<maxl; j++)
for (int i=1; i<=Time; i++)
{
int mid=min(i+(1<<(j-1)),Time);
if (dep[ ST[i][j-1] ]<dep[ ST[mid][j-1] ]) ST[i][j]=ST[i][j-1];
else ST[i][j]=ST[mid][j-1];
}
Lg[1]=0;
for (int i=2; i<=Time; i++) Lg[i]=Lg[i>>1]+1;

for (int i=1; i<=n; i++) Rank[i]=i;
sort(Rank+1,Rank+n+1,Comp);
for (int i=1; i<=n; i++)
{
int node=Rank[i];
int max_d=(int)floor( sqrt( (double)a[node] )+0.001 );
for (int d=1; d<=max_d; d++)
if (a[node]%d==0)
{
Node[d].push_back(node);
if (d!=a[node]/d) Node[ a[node]/d ].push_back(node);
}
}

for (int d=1; d<=n; d++)
{
cnt=0;
for (int i=0; i<Node[d].size(); i++) tree[++cnt]=Node[d][i];

tail=1;
sak[1]=tree[1];
for (int i=2; i<=Node[d].size(); i++)
{
int x=tree[i],last=0,p=Lca(sak[tail],x);
while ( dep[ sak[tail] ]>dep[p] && tail ) last=sak[tail--];
if (sak[tail]!=p) Fa[p]=sak[tail],sak[++tail]=tree[++cnt]=p;
if (last) Fa[last]=p;
Fa[x]=p;
sak[++tail]=x; //!!!
}
int root=sak[1];
Fa[root]=0;

cur=0;
for (int i=1; i<=cnt; i++) head[ tree[i] ]=NULL;
for (int i=1; i<=cnt; i++)
{
int x=tree[i];
if (i<=Node[d].size()) Size[x]=phi[ a[x] ];
else Size[x]=0;
}

Calc(root);
LL tot=Size[root],temp=0;
for (int i=1; i<=cnt; i++)
{
int x=tree[i];
if (x==root) continue;
temp=(temp+ Size[x]*(tot-Size[x]+M)%M*(dep[x]-dep[ Fa[x] ])%M )%M; //!!!
}
temp=temp*G[d]%M;
ans=(ans+temp)%M;
}

ans=ans*rev[n]%M;
ans=ans*rev[n-1]%M;
ans=ans*2LL%M;
printf("%I64d\n",ans);

return 0;
}

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客