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(缓存)的主要内容,如果未能解决你的问题,请参考以下文章

uoj#33. UR #2树上GCD

uoj33 UR #2树上GCD

UOJ树上gcd

uoj#370UR #17滑稽树上滑稽果

UOJ #62. UR #5怎样跑得更快

UOJ83UR #7水题出题人(提交答案题)