• 【uoj33】 UR #2—树上GCD


    http://uoj.ac/problem/33 (题目链接)

    题意

      给出一棵${n}$个节点的有根树,${f_{u,v}=gcd(dis(u,lca(u,v)),dis(v,lca(u,v)))}$,求对于${1<=i<=n-1,}$有多少${f_{u,v}=i}$。

    Solution

      虽然有官方题解,但是感觉写的并不是很详细→_→,不过自己推敲推敲还是能懂的。而且这道题细节也很多,膜拜了DaD3zZ大爷的代码完全弄懂。。

      具体的一些实现细节就看看代码吧。(本来想详细的写写的,然而语文太差了,写了一半感觉发出来估计没什么人看得懂→_→)

      ${ans[i]}$表示公约数为${i}$的点对数目,${ANS[i]}$表示最大公约数为${i}$的点对数目。

    细节

      竟然1A了w(゚Д゚)w

    代码

    // uoj33
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf 100000000
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=200010;
    int head[maxn],f[maxn],size[maxn],deep[maxn],vis[maxn],fa[maxn];
    int Dargen,n,m,sum,cnt,maxd,maxD,block;
    LL NUM[maxn],num[maxn],Cnts[maxn],cnts[maxn],ans[maxn],ANS[maxn],F[500][500];
    
    struct edge {int to,next;}e[maxn<<1];
    
    void link(int u,int v) {
    	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    void caldargen(int x,int fa) {
    	f[x]=0;size[x]=1;
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
    			caldargen(e[i].to,x);
    			size[x]+=size[e[i].to];
    			f[x]=max(f[x],size[e[i].to]);
    		}
    	f[x]=max(f[x],sum-size[x]);
    	if (f[x]<f[Dargen]) Dargen=x;
    }
    void caldeep(int x,int fa) {
    	cnts[deep[x]]++;
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
    			deep[e[i].to]=deep[x]+1;
    			caldeep(e[i].to,x);
    		}
    }
    void work(int x) {
    	vis[x]=1;maxd=maxD=0;
    	for (int d,i=head[x];i;i=e[i].next) if (e[i].to!=fa[x] && !vis[e[i].to]) {
    			deep[e[i].to]=1;caldeep(e[i].to,x);
    			for (d=0;cnts[d+1];d++);
    			maxd=max(maxd,d);
    			for (int j=1;j<=d;j++)
    				for (int k=j;k<=d;k+=j) num[j]+=cnts[k];
    			for (int j=1;j<=d;j++) ans[j]+=num[j]*NUM[j],ANS[j]+=cnts[j];
    			for (int j=1;j<=d;j++) Cnts[j]+=cnts[j],NUM[j]+=num[j],num[j]=cnts[j]=0;
    		}
    	Cnts[0]=1;int tt=0,D=1;
    	for (int p=x,i=fa[x];i>=1 && !vis[i];p=i,i=fa[i],D++) {
    		maxD=0;
    		for (int d,j=head[i];j;j=e[j].next) if (e[j].to!=fa[i] && !vis[e[j].to] && e[j].to!=p) {
    				deep[e[j].to]=1;caldeep(e[j].to,i);
    				for (d=0;cnts[d+1];d++);
    				maxD=max(maxD,d);
    			}
    		for (int k=1;k<=maxD;k++)
    			for (int l=k;l<=maxD;l+=k) num[k]+=cnts[l];
    		tt=max(tt,maxD);
    		for (int j=1;j<=min(block,maxD);j++) {
    			if (F[j][D%j]==-1) {
    				F[j][D%j]=0;
    				for (int k=j-(D-1)%j-1;k<=maxd;k+=j) F[j][D%j]+=Cnts[k];
    			}
    			ans[j]+=F[j][D%j]*num[j];
    		}
    		for (int j=block+1;j<=maxD;j++) {
    			LL tmp=0;
    			for (int k=j-(D-1)%j-1;k<=maxd;k+=j) tmp+=Cnts[k];
    			ans[j]+=tmp*num[j];
    		}
    		for (int i=1;i<=maxD;i++) num[i]=cnts[i]=0;
    	}
    	D--;int l=0,r=-1;LL tmp=0;
    	for (int i=1;i<=D+maxd;i++) {
    		tmp+=r+1<i ? Cnts[++r] : 0;
    		tmp-=l<i-D ? Cnts[l++] : 0;
    		ANS[i]+=tmp;
    	}
    	for (int i=1;i<=min(block,tt);i++)
    		for (int j=0;j<=D;j++) F[i][j]=-1;
    	for (int i=0;i<=maxd;i++) NUM[i]=Cnts[i]=0;
    	for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
    			sum=size[e[i].to];Dargen=0;
    			caldargen(e[i].to,0);
    			work(Dargen);
    		}
    }
    
    int main() {
    	scanf("%d",&n);
    	block=(int)sqrt(n)+0.5;
    	for (int i=2;i<=n;i++) {
    		scanf("%d",&fa[i]);
    		link(fa[i],i);
    	}
    	memset(F,-1,sizeof(F));
    	f[Dargen=0]=inf;sum=n;
    	caldargen(1,0);
    	work(Dargen);
    	for (int i=n-1;i>=1;i--)
    		for (int j=i+i;j<=n-1;j+=i) ans[i]-=ans[j];
    	for (int i=1;i<n;i++) printf("%lld
    ",ans[i]+ANS[i]);
    	return 0;
    }
    

      

  • 相关阅读:
    python re模块
    python
    python
    Django学习手册
    Django学习手册
    前端
    前端
    Django学习手册
    前端
    Database学习
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6357708.html
Copyright © 2020-2023  润新知