# CF809E Surprise me!

phi(x*y)就是phi(x)*phi(y)*gcd(x,y)/phi(gcd(x,y))其实就是把公共质因子的(1-1/p)这些东西除掉

1.O(1)LCA是快，但是注意ST判断i+(1<<j)-1<=cnt，还有lim是cnt不是n！

2.虚树还是注意mem[i]不是i

3.明确枚举的公共质因子而不是gcd！

#include<bits/stdc++.h>
#define reg register int
#define il inline
#define fi first
#define se second
#define mk(a,b) make_pair(a,b)
#define numb (ch^'0')
#define pb push_back
#define solid const auto &
#define enter cout<<endl
#define pii pair<int,int>
// #define int long long
using namespace std;
typedef long long ll;
template<class T>il void rd(T &x){
char ch;x=0;bool fl=false;while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
for(x=numb;isdigit(ch=getchar());x=x*10+numb);(fl==true)&&(x=-x);}
template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');}
namespace Modulo{
const int mod=1e9+7;
int mul(int x,int y){return (ll)x*y%mod;}
void inc2(int &x,int y){x=mul(x,y);}
int qm(int x,int y=mod-2){int ret=1;while(y){if(y&1) ret=mul(x,ret);x=mul(x,x);y>>=1;}return ret;}
}
using namespace Modulo;
namespace Miracle{
const int N=400000+5;
int n,d;
struct node{
int nxt,to;
}e[2*N];
int hd[N],cnt;
int val[N];
e[++cnt].nxt=hd[x];
e[cnt].to=y;
hd[x]=cnt;
}
bool vis[N];
int pri[N],tot;
int phi[N];
int mindiv[N];
int inv[N];
int miu[N];
void sieve(int n){
phi[1]=1;
miu[1]=1;
for(reg i=2;i<=n;++i){
if(!vis[i]){
pri[++tot]=i;
phi[i]=i-1;
mindiv[i]=i;
miu[i]=-1;
}
for(reg j=1;j<=tot;++j){
if(i*pri[j]>n) break;
vis[i*pri[j]]=1;
mindiv[i*pri[j]]=pri[j];
if(i%pri[j]==0){
phi[i*pri[j]]=phi[i]*pri[j];
miu[i*pri[j]]=0;
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
miu[i*pri[j]]=-miu[i];
}
}
}
int dfn[N],dfn2[N],dep[N];
int a[2*N],ca,lg[2*N];
int mx[2*N][19];
int fr[N];

int fa[N];
int df;
int mem[N],num;
int div[N];
ll con,ans,sum;
int sta[N],top;
bool cmp(int x,int y){
return dfn[x]<dfn[y];
}
void dfs(int x){
// cout<<" dfs "<<x<<" fa "<<fa[x]<<endl;
dfn[x]=++df;
a[++ca]=x;
fr[x]=ca;
dep[x]=dep[fa[x]]+1;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
if(y==fa[x]) continue;
fa[y]=x;
dfs(y);
a[++ca]=x;
}
dfn2[x]=df;
}
int lca(int x,int y){
if(x==y) return x;
x=fr[x];y=fr[y];
int len=y-x+1;
int a=mx[x][lg[len]],b=mx[y-(1<<lg[len])+1][lg[len]];
return dep[a]<dep[b]?a:b;
}
int f[N];
void dp(int x,int fa){
// cout<<" dp "<<x<<" "<<fa<<endl;
if(x%d==0) f[x]=phi[x];
else f[x]=0;
for(reg i=hd[x];i;i=e[i].nxt){
int y=e[i].to;
dp(y,x);
}
if(fa){
}
}
int main(){
rd(n);
sieve(n);
inv[1]=1;
for(reg i=2;i<=n;++i){
inv[i]=mul(mod-mod/i,inv[mod%i]);
}
for(reg i=1;i<=n;++i){
rd(val[i]);
}
int x,y;
for(reg i=1;i<n;++i){
rd(x);rd(y);
x=val[x],y=val[y];
}
dfs(1);
for(reg i=1;i<=2*n;++i){
lg[i]=(i>>(lg[i-1]+1)?lg[i-1]+1:lg[i-1]);
}
// cout<<"ca "<<ca<<endl;
// prt(a,1,ca);
// prt(fr,1,n);

for(reg i=1;i<=ca;++i){
mx[i][0]=a[i];
}
for(reg j=1;j<=18;++j){
for(reg i=1;i+(1<<j)-1<=ca;++i){
mx[i][j]=(dep[mx[i][j-1]]>dep[mx[i+(1<<(j-1))][j-1]]?mx[i+(1<<(j-1))][j-1]:mx[i][j-1]);
// cout<<" mx i j "<<i<<" "<<j<<" : "<<mx[i][j]<<endl;
}
}

cnt=0;tot=0;
memset(hd,0,sizeof hd);
for(d=1;d<=n;++d){
// cout<<"--------d "<<d<<endl;
if(!miu[d]) continue;
con=0;tot=0;
sum=0;
int lp=d;
while(lp!=1){
int pr=mindiv[lp];
div[tot++]=pr;
while(mindiv[lp]==pr) lp/=pr;
}
for(reg s=0;s<(1<<tot);++s){
int now=1;
for(reg i=0;i<tot;++i){
if(s&(1<<i)) now=mul(now,mul(div[i],inv[div[i]-1]));
}
// cout<<" now "<<now<<endl;
if((tot-__builtin_popcount(s))&1){
}

// cout<<" con "<<con<<endl;

cnt=0;tot=0,num=0;
for(reg j=d;j<=n;j+=d){
mem[++num]=j;
}
sort(mem+1,mem+num+1,cmp);
int od=num;
for(reg i=1;i<od;++i){
int anc=lca(mem[i],mem[i+1]);
// cout<<mem[i]<<" "<<mem[i+1]<<" anc "<<anc<<endl;
mem[++num]=anc;
}
sort(mem+1,mem+num+1,cmp);
top=0;
mem[0]=0;
for(reg i=1;i<=num;++i){
if(mem[i]==mem[i-1]) continue;
int x=mem[i];
while(top&&!(dfn[sta[top]]<=dfn[x]&&dfn2[x]<=dfn2[sta[top]])) --top;
if(top) {
}
sta[++top]=x;
}
// cout<<" pre "<<top<<" "<<num<<endl;
dp(mem[1],0);
// cout<<" over "<<endl;
//clear
for(reg i=1;i<=num;++i){
hd[mem[i]]=0;f[mem[i]]=0;
}
cnt=0;
// cout<<" ans "<<ans<<endl;
// memset(hd,0,sizeof hd);
}
// cout<<" ans "<<ans<<endl;
ll mom=mul(n,n-1);
ans=mul(ans,2);
ans=mul(ans,qm(mom));
ot(ans);
return 0;
}

}
signed main(){
Miracle::main();
return 0;
}

/*
Author: *Miracle*
*/

posted @ 2019-05-23 22:28  *Miracle*  阅读(146)  评论(0编辑  收藏  举报