#点分治,根号分治#UOJ 33【UR #2】树上GCD
分析
如果 \(lca(x,y)=x\) 或 \(y\),这种情况答案就是深度之差,直接特判。
否则 \(x,y\) 隶属于两个不同的子树,考虑点分治,那么 \(x,y\) 只可能同时是 \(root\) 的子孙
或一个是 \(root\) 的祖先的另一个子孙(包括本身)另一个隶属于 \(root\) 的子树。
由于 \(\gcd\) 比较难处理,转化为求倍数的答案最后再减掉。对于第一种情况比较简单,
考虑第二种情况,到 \(lca\) 的距离会改变,但是到 \(root\) 的距离不变,因此根据另一个点到 \(lca\) 的距离进行根号分治,
小于等于阈值的预处理,否则直接从余数开始不断加步长,都是一个根号,再加上之前的一种情况也就是 \(O(n\log^2n+n\sqrt n)\)
代码
#include <cstdio>
#include <cctype>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=200011; typedef long long lll; struct node{int y,next;}e[N<<1];
int big[N],siz[N],SIZ,fat[N],root,n,as[N],v[N],dep[N],c[N],mx,MX; lll ans[N],sc[N],s[64][64];
int iut(){
int ans=0; char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=ans*10+c-48,c=getchar();
return ans;
}
void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
void dfs(int x,int fa){
siz[x]=1,big[x]=0;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y]){
dfs(e[i].y,x);
siz[x]+=siz[e[i].y];
big[x]=max(big[x],siz[e[i].y]);
}
big[x]=max(big[x],SIZ-siz[x]);
if (big[x]<=big[root]) root=x;
}
void DFS(int x,int fa,int dep){
++c[dep];
if (dep>MX) MX=dep;
for (int i=as[x];i;i=e[i].next)
if (e[i].y!=fa&&!v[e[i].y])
DFS(e[i].y,x,dep+1);
}
void calc(int x){
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]&&fat[e[i].y]==x){
DFS(e[i].y,x,1);
for (int j=1;j<=MX;++j)
for (int k=j*2;k<=MX;k+=j)
c[j]+=c[k];
for (int j=1;j<=MX;++j)
ans[j]+=c[j]*sc[j],sc[j]+=c[j],c[j]=0;
if (MX>mx) mx=MX;
MX=0;
}
}
void CALC(int x,int rt){
int las=x,D=1,bl=sqrt(mx)/7+1;
for (int i=mx>>1;i;--i)
for (int j=i*2;j<=mx;j+=i) sc[i]-=sc[j];
++sc[0];
for (int i=0;i<=mx;++i) if (sc[i])
for (int j=1;j<=bl;++j) s[j][i%j]+=sc[i];
for (int X=fat[x];X!=fat[rt];las=X,X=fat[X],++D){
for (int i=as[X];i;i=e[i].next)
if (!v[e[i].y]&&fat[e[i].y]==X&&e[i].y!=las) DFS(e[i].y,X,1);
for (int j=1;j<=MX;++j)
for (int k=j*2;k<=MX;k+=j)
c[j]+=c[k];
for (int j=1;j<=bl;++j) ans[j]+=c[j]*s[j][(j-D%j)%j],c[j]=0;
for (int j=bl+1;j<=MX;++j)
if (c[j]){
lll sum=0;
for (int k=(j-D%j)%j;k<=mx;k+=j) sum+=sc[k];
ans[j]+=c[j]*sum,c[j]=0;
}
MX=0;
}
for (int j=1;j<=bl;++j)
for (int i=0;i<j;++i) s[j][i]=0;
}
void dp(int x,int rt){
v[x]=1,mx=0,calc(x);
if (x!=rt) CALC(x,rt);
for (int i=0;i<=mx;++i) sc[i]=0;
for (int i=as[x];i;i=e[i].next)
if (!v[e[i].y]){
big[0]=SIZ=siz[e[i].y];
dfs(e[i].y,root=0);
dp(root,fat[x]==e[i].y?rt:e[i].y);
}
}
int main(){
n=iut();
for (int i=2;i<=n;++i){
fat[i]=iut(),dep[i]=dep[fat[i]]+1;
e[i]=(node){i,as[fat[i]]},as[fat[i]]=i;
e[i+n-1]=(node){fat[i],as[i]},as[i]=i+n-1;
}
big[0]=SIZ=n,dfs(1,root=0),dfs(root,0),dp(root,1);
for (int i=n>>1;i;--i)
for (int j=i*2;j<=n;j+=i) ans[i]-=ans[j];
sc[1]=n-1;
for (int i=2;i<=n;++i) --sc[dep[i]+1];
for (int i=1;i<=n;++i) sc[i]+=sc[i-1];
for (int i=1;i<n;++i) print(ans[i]+sc[i]),putchar(10);
return 0;
}

浙公网安备 33010602011771号