uoj33 [UR # 2] tree GCD

topic

Generally long section + \ (\ RM the DSU \ ON \ Tree \) thinking

Do a conversion, to respect \ (i \ in [1, n-1] \) is determined how many \ (f (u, v) \) satisfies \ (i | f (u, v) \) so that we do a final like inversion

Now we ask how many of \ (f (u, v) \) is \ (i \) or \ (i \) multiples, we need to quickly merge information at the time of the long sides of the cross, this information looks very chic , shaped like the current node distance \ (I \) or \ (I \) number of nodes of the multiple

Fortunately, that son too light, we direct violence harmonic series can handle it, but this information is very bad from where his son inherited

Consider the root partition

If this \ (i> \ sqrt {the n-} \) , which is direct violence severely son where violence complexity is \ (\ FRAC {the n-} {i} <\ sqrt {the n-} \) , so we naturally can directly use long section of the array get when maintenance

But \ (i \ leq \ sqrt { n} \) when considering an array of maintenance can quickly get this information, but such an array heavier son there is no way to inherit, it looks as if the line is not long cross pass

This time you need to use \ (\ rm dsu \) thought the

Consider maintaining a \ (g [i] [j ] \) represents an idea tree internal point depth \ (i \) modulo remainder is \ (j \) the number of points, so we do not need to consider how to inherit like his son did not re-emptied directly used enough

We are very convenient to use this array internal inquiry sub-tree node to the current distance \ (i \) or \ (i \) the number of multiple points, just use the depth of the current point engage in a practice on it

When we light the son of violence can be directly updated \ (G \) , updated every complexity is \ (O (\ sqrt {n }) \) of

But in general, it is the first long section and then re-light the son of the son, but \ (\ rm dsu \) is the son of the first light and then heavy son, here in order to ensure \ (g \) information in the maintenance comes from sub-tree internally, we have to like \ (\ rm dsu \) to treat heavy as the first light after the son of the son

Code

#include<bits/stdc++.h>
#define re register
#define LL long long
#define min(a,b) ((a)<(b)?(a):(b))
inline int read() {
    char c=getchar();int x=0;while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
const int maxn=2e5+5;
struct E{int v,nxt;}e[maxn];
int n,num,__,B;
int head[maxn],son[maxn],len[maxn],dep[maxn],f[maxn],mu[maxn],p[maxn>>1];
int h[maxn],top[maxn],dfn[maxn],g[320][320],b[maxn],c[maxn];
LL ans[maxn],Ans[maxn];
inline void add(int x,int y) {
    e[++num].v=y;e[num].nxt=head[x];head[x]=num;
}
void dfs1(int x) {
    for(re int i=head[x];i;i=e[i].nxt) {
        dep[e[i].v]=dep[x]+1;dfs1(e[i].v);
        if(len[e[i].v]>len[son[x]]) son[x]=e[i].v;
    }
    len[x]=len[son[x]]+1;
}
void dfs2(int x,int topf) {
    top[x]=topf,dfn[x]=++__;
    if(!son[x]) return;
    dfs2(son[x],topf);
    for(re int i=head[x];i;i=e[i].nxt) 
    if(son[x]!=e[i].v) dfs2(e[i].v,e[i].v);
}
inline void ins(int x,int v) {
    for(re int i=1;i<=B;++i) g[i][x%i]+=v;
}
inline int calc(int x,int k) {
    if(k<=B) return g[k][dep[x]%k];
    int tot=0;
    for(re int i=dfn[x]+k;i<=dfn[x]+len[x]-1;i+=k) tot+=h[i];
    return tot;
}
void dfs(int x) {
    for(re int i=head[x];i;i=e[i].nxt) 
    if(son[x]!=e[i].v) dfs(e[i].v);
    if(son[x]) dfs(son[x]);
    for(re int i=head[x];i;i=e[i].nxt) {
        if(son[x]==e[i].v) continue;
        int y=e[i].v;
        for(re int j=1;j<=len[y];++j)
            b[j]=h[dfn[y]+j-1];
        for(re int j=1;j<=len[y];++j)
            for(re int k=j;k<=len[y];k+=j) c[j]+=b[k];
        for(re int j=1;j<=len[y];++j)
            ans[j]+=1ll*c[j]*calc(x,j);
        for(re int j=1;j<=len[y];++j) c[j]=b[j]=0;
        for(re int j=1;j<=len[y];++j)
            ins(j+dep[y]-1,h[dfn[y]+j-1]),h[dfn[x]+j]+=h[dfn[y]+j-1];
    }
    ins(dep[x],1);h[dfn[x]]++;
    if(x==top[x]) {
        for(re int i=1;i<=B;++i)
            for(re int j=dep[x];j<=dep[x]+len[x]-1;++j)
                g[i][j%i]=0;
    }
}
int main() {
    n=read();
    for(re int x,i=2;i<=n;++i) x=read(),add(x,i);
    dep[1]=1,dfs1(1),dfs2(1,1);f[1]=mu[1]=1;
    B=std::ceil(std::sqrt(n));B=min(B,310);dfs(1);
    for(re int i=2;i<=n;i++) {
        if(!f[i]) p[++p[0]]=i,mu[i]=-1;
        for(re int j=1;j<=p[0]&&p[j]*i<=n;++j) {
            f[p[j]*i]=1;if(i%p[j]==0) break;
            mu[p[j]*i]=-mu[i];
        }
    }
    for(re int i=1;i<=n;i++)
        for(re int j=i;j<=n;j+=i)
            Ans[i]+=1ll*mu[j/i]*ans[j];
    for(re int i=2;i<=n;++i) 
        c[1]++,c[dep[i]]--;
    for(re int i=1;i<=n;i++) c[i]+=c[i-1];
    for(re int i=1;i<n;i++) printf("%lld\n",Ans[i]+c[i]);
    return 0;
}

Guess you like

Origin www.cnblogs.com/asuldb/p/11487538.html
gcd