UOJ UR#2树上GCD(缓存)
Posted DaD3zZ
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了UOJ UR#2树上GCD(缓存)相关的知识,希望对你有一定的参考价值。
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> #include<cstring> using namespace std; int read() { int x=0,f=1; char ch=getchar(); while (ch<‘0‘ || ch>‘9‘) {if (ch==‘-‘) f=-1; ch=getchar();} while (ch>=‘0‘ && ch<=‘9‘) {x=x*10+ch-‘0‘; ch=getchar();} return x*f; } #define maxn 200010 int n,m,fa[maxn],root,tmp,block,siz; struct EdgeNode{int next,to;}edge[maxn<<1]; int head[maxn],cnt; void add(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;} void insert(int u,int v) {fa[v]=u; add(u,v); add(v,u);} int size[maxn],maxx[maxn]; bool visit[maxn]; void Getroot(int now,int fa) { size[now]=1; maxx[now]=0; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=fa && !visit[edge[i].to]) { Getroot(edge[i].to,now); size[now]+=size[edge[i].to]; maxx[now]=max(maxx[now],size[edge[i].to]); } maxx[now]=max(maxx[now],siz-size[now]); if (maxx[now]<maxx[root]) root=now; } int num[maxn],deep[maxn]; void DFSdeep(int now,int fa) { num[deep[now]]++; for (int i=head[now]; i; i=edge[i].next) if (edge[i].to!=fa && !visit[edge[i].to]) { deep[edge[i].to]=deep[now]+1; DFSdeep(edge[i].to,now); } if (deep[now]>tmp) tmp=deep[now]; } long long S[maxn],Ans[maxn],ans[maxn],tim[maxn],Num[maxn],Tim[maxn],f[510][510]; void GetAns(int now) { visit[now]=1; int maxd=0,Maxd=0; for (int i=head[now]; i; i=edge[i].next) if (!visit[edge[i].to] && edge[i].to!=fa[now]) { deep[edge[i].to]=1; tmp=0; DFSdeep(edge[i].to,now); if (tmp>maxd) maxd=tmp; for (int j=1; j<=tmp; j++) for (int k=j; k<=tmp; k+=j) tim[j]+=num[k]; for (int j=1; j<=tmp; j++) Num[j]+=num[j],Ans[j]+=num[j],S[j]+=tim[j]*Tim[j], Tim[j]+=tim[j],tim[j]=0,num[j]=0; } Num[0]=1; int zz=0,ss=now; for (int i=fa[now]; !visit[i]; ss=i,i=fa[i]) { tmp=0; zz++; for (int j=head[i]; j; j=edge[j].next) if (edge[j].to!=fa[i] && !visit[edge[j].to] && edge[j].to!=ss) deep[edge[j].to]=1,DFSdeep(edge[j].to,i); if (tmp>Maxd) Maxd=tmp; for (int j=1; j<=tmp; j++) for (int k=j; k<=tmp; k+=j) tim[j]+=num[k]; int tt=tmp<block?tmp:block; for (int j=1; j<=tt; j++) { if (f[j][zz%j]==-1) { f[j][zz%j]=0; for (int k=(j-zz%j)%j; k<=maxd; k+=j) f[j][zz%j]+=Num[k]; } S[j]+=f[j][zz%j]*tim[j]; } for (int j=block+1; j<=tmp; j++) for (int k=(j-zz%j)%j; k<=maxd; k+=j) S[j]+=Num[k]*tim[j]; for (int j=1; j<=tmp; j++) tim[j]=0,num[j]=0; Ans[zz]++; } int l=1,r=0; long long tmpans=0; for (int i=2; i<=zz+maxd; i++) tmpans+=r+1<i?Num[++r]:0,tmpans-=l+zz<i?Num[l++]:0,Ans[i]+=tmpans; int tt=Maxd<block?Maxd:block; for (int i=1; i<=tt; i++) for (int j=0; j<=i-1; j++) f[i][j]=-1; for (int i=0; i<=maxd; i++) tim[i]=0,Tim[i]=0; for (int i=head[now]; i; i=edge[i].next) if (!visit[edge[i].to]) { root=0; siz=size[edge[i].to]; Getroot(edge[i].to,now); GetAns(root); } } void Freopen() {freopen("TreeGCD.in","r",stdin);freopen("TreeGCD.out","w",stdout);} void Fclose() {fclose(stdin);fclose(stdout);} int main() { n=read(); block=(int)sqrt(n); for (int x,i=1; i<=n-1; i++) x=read(),insert(x,i); maxx[root]=0x7fffffff; siz=n; memset(f,-1,sizeof(f)); Getroot(1,0); GetAns(root); for (int i=n-1; i; i--) { ans[i]=S[i]; for (int j=i+i; j<=n-1; j+=i) ans[i]-=ans[j]; } for (int i=1; i<=n-1; i++) printf("%I64d\n",ans[i]+Ans[i]); return 0; }
以上是关于UOJ UR#2树上GCD(缓存)的主要内容,如果未能解决你的问题,请参考以下文章