zoukankan      html  css  js  c++  java
  • 【UOJ#33】【UR #2】树上GCD(长链剖分,分块)

    【UOJ#33】【UR #2】树上GCD(长链剖分,分块)

    题面

    UOJ

    题解

    首先不求恰好,改为求(i)的倍数的个数,最后容斥一下就可以解决了。
    那么我们考虑枚举一个(LCA)位置,在其两棵不同的子树中选择两个点,那么贡献就是这两段的(gcd)
    那么发现要统计的东西类似于(u)的子树中,深度为(d)的点的个数,这个可以很容易的用长链剖分来维护,那么维护出这个数组之后就可以(O(log {dep}))的对于贡献进行计算。然而这个复杂度是假的,因为你每次都需要一次(O(log dep)),这个(dep)不能是长链的(dep),而这里却是长链长度,所以这样子复杂度不正确,
    那么考虑别的方法,那就分块。
    对于(disge sqrt n)的情况,因为其倍数的个数只有(sqrt n)个,所以直接暴力统计,这部分全局的总复杂度是(O(nsqrt n))
    对于(dislt sqrt n),维护(g[i][j])表示当前重链的所有子树中,深度模(i)(j)的点的个数,这个东西可以在因为(dislt sqrt n),所以每次(O(sqrt n))的加入就行了,这样子全局复杂度也是(O(nsqrt n))
    这样子复杂度就做到了(O(nsqrt n))

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MAX 200200
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Line{int v,next;}e[MAX];int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    int n,hson[MAX],md[MAX],dep[MAX];
    void dfs1(int u,int ff)
    {
    	md[u]=dep[u]=dep[ff]+1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		dfs1(v,u);
    		if(md[v]>md[hson[u]])hson[u]=v;
    	}
    	if(hson[u])md[u]=md[hson[u]];
    }
    int tmp[MAX<<2],*f[MAX],*id=tmp,t[MAX],g[355][355],BLK=350;
    ll ans[MAX],pre[MAX];
    void dfs(int u,int ff,int fl)
    {
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff||v==hson[u])continue;
    		f[v]=id;id+=md[v]-dep[v]+1;dfs(v,u,0);
    	}
    	if(hson[u])f[hson[u]]=f[u]+1,dfs(hson[u],u,1);
    	f[u][0]=1;int mx=md[u]-dep[u];
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff||v==hson[u])continue;
    		int s=md[v]-dep[v]+1;
    		for(int j=1;j<=s;++j)t[j]=f[v][j-1];
    		for(int j=1;j<=s;++j)
    			for(int k=j+j;k<=s;k+=j)
    				t[j]+=t[k];
    		for(int j=1;j<=s;++j)
    			if(j>BLK)for(int k=j;k<=mx;k+=j)ans[j]+=1ll*f[u][k]*t[j];
    			else ans[j]+=1ll*g[j][dep[u]%j]*t[j];
    		for(int j=0;j<s;++j)f[u][j+1]+=f[v][j];
    		for(int j=dep[v];j<=md[v];++j)
    			for(int k=1;k<=BLK;++k)
    				g[k][j%k]+=f[v][j-dep[v]];
    	}
    	for(int i=1;i<=BLK;++i)++g[i][dep[u]%i];
    	if(!fl)
    		for(int k=1;k<=BLK;++k)
    			for(int j=dep[u];j<=md[u];++j)
    				g[k][j%k]=0;
    }
    int main()
    {
    	n=read();
    	for(int i=2,x;i<=n;++i)x=read(),Add(x,i);
    	dfs1(1,0);f[1]=id;id+=md[1]+1;dfs(1,0,0);
    	for(int i=n;i;--i)
    		for(int j=i+i;j<=n;j+=i)
    			ans[i]-=ans[j];
    	for(int i=2;i<=n;++i)pre[dep[i]-1]+=1;
    	for(int i=n;i;--i)pre[i]+=pre[i+1];
    	for(int i=1;i<n;++i)printf("%lld
    ",ans[i]+pre[i]);
    	return 0;
    }
    
  • 相关阅读:
    十:Webpack 引入bootstrap
    九:Webpack结合ES6
    pfx格式密钥库修改密码
    邮件发送接收工具
    用keytool制作证书并在tomcat配置https服务(四)
    用keytool制作证书并在tomcat配置https服务(三)
    用keytool制作证书并在tomcat配置https服务(二 )
    用keytool制作证书并在tomcat配置https服务(一)
    java全角和半角转换
    RC4加密解密
  • 原文地址:https://www.cnblogs.com/cjyyb/p/11049079.html
Copyright © 2011-2022 走看看