• 点分治总结


    点分治总结

    开坑。

    做几道例题之后填。

    噫噫噫没例题做

    好像都出动态点分治去了(Orz)

    下面是分割线!

    上面是分割线!

    点分治

    瞎BB一个:点分治适用于处理树上路径的统计问题。

    eg. 问你一棵树上距离为k的点对数量。

    思想

    一棵有根树上的路径只有两种:过根的和不过根的。

    如果是过根的,可以(O(n))解决。

    处理完过根的路径之后,这个树根没有用了,所以删掉。树被分成了若干个联通块,递归下去处理即可。

    期望(O(nlog_2n))

    实现步骤

    思想都有了你还不会实现吗辣鸡

    1. 选一个树根,将无根树转化为有根树。
      如果随便选根可能会GG,一条链把你卡成(O(n^2))
      要保证复杂度,树根必须是树的重心。不证。
      重心求法不写。
      const int&这东西好像卡常有点用就用了。
      siz[i]是i子树的大小。
      f[i]是i最大儿子的子树大小。
      vis[i]是删除标记。
        il vd getrt(const int&x,const int&FA){
           siz[x]=1;f[x]=0;
           for(rg int i=fir[x];i;i=nxt[i]){
            	if(FA==dis[i]||vis[dis[i]])continue;
           	    getrt(dis[i],x);
            	siz[x]+=siz[dis[i]];
            	f[x]=max(f[x],siz[dis[i]]);
            }
            f[x]=max(f[x],sum-siz[x]);
        	if(f[x]<f[rt])rt=x;
        }
        il vd Getrt(const int&x,const int&_sum){sum=_sum,f[0]=2e9,rt=0,getrt(x,-1);}
        //在包括x的,点数为_sum联通块中选根
    
    1. 统计这个联通块过根的路径。
      以上面的eg为例。
      先处理出所有点到根节点的距离。
        il vd getdep(const int&x,const int&FA){
        	dep[++dep[0]]=dp[x];
        	for(rg int i=fir[x];i;i=nxt[i]){
        		if(vis[dis[i]]||dis[i]==FA)continue;
        		dp[dis[i]]=dp[x]+w[i];
        		getdep(dis[i],x);
        	}
        }
        getdep(x,-1);
    

    然后用尺取法(?)算出深度和<=k的点对数,累加进ans。
    这种方法可能会有同一棵子树(没有过根)的点对被计入,所以再去掉那些点对即可。

        il int cal(const int&x,const int&d){
        	dp[x]=d;dep[0]=0;getdep(x,-1);
        	sort(dep+1,dep+dep[0]+1);
        	sta int l,r,tot;l=1,r=dep[0],tot=0;
        	while(l<r)(dep[l]+dep[r]<=k)?(tot+=r-l,++l):--r;
        	return tot;
        }
        x=Getrt();
        ans+=cal(x,0);
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(vis[dis[i]])continue;
    		ans-=cal(dis[i],w[i]);
    	}
    
    1. 删除根节点。
        vis[rt]=0;
    
    1. 递归下去,处理子树。

    几道例题

    cogs1714(eg):

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define il inline
    #define rg register
    #define vd void
    #define sta static
    typedef long long ll;
    using namespace std;
    il int gi(){
    	rg int x=0,f=1;rg char ch=getchar();
    	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    const int maxn=10001;
    int rt,n,k,fir[maxn],nxt[maxn<<1],dis[maxn<<1],w[maxn<<1],id,ans,f[maxn],siz[maxn],sum,vis[maxn];
    int dp[maxn],dep[maxn];
    il vd link(int&a,int&b,int&c){nxt[++id]=fir[a],fir[a]=id,dis[id]=b,w[id]=c;}
    il vd getrt(const int&x,const int&FA){
    	siz[x]=1;f[x]=0;
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(vis[dis[i]]||dis[i]==FA)continue;
    		getrt(dis[i],x);
    		siz[x]+=siz[dis[i]];
    		f[x]=max(f[x],siz[dis[i]]);
    	}
    	f[x]=max(f[x],sum-siz[x]);
    	if(f[x]<f[rt])rt=x;
    }
    il vd getdep(const int&x,const int&FA){
    	dep[++dep[0]]=dp[x];
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(vis[dis[i]]||dis[i]==FA)continue;
    		dp[dis[i]]=dp[x]+w[i];
    		getdep(dis[i],x);
    	}
    }
    il int cal(const int&x,const int&d){
    	dp[x]=d;dep[0]=0;getdep(x,-1);
    	sort(dep+1,dep+dep[0]+1);
    	sta int l,r,tot;l=1,r=dep[0],tot=0;
    	while(l<r)(dep[l]+dep[r]<=k)?(tot+=r-l,++l):--r;
    	return tot;
    }
    il vd Getrt(const int&x,const int&_sum){sum=_sum,f[0]=2e9,rt=0,getrt(x,-1);}
    il vd solve(const int&x){
    	ans+=cal(x,0);vis[x]=1;
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(vis[dis[i]])continue;
    		ans-=cal(dis[i],w[i]);
    		Getrt(dis[i],siz[dis[i]]);
    		solve(rt);
    	}
    }
    int main(){
    	int x,y,z;
    	while(n=gi(),k=gi(),n){
    		id=0;memset(fir,0,sizeof fir);memset(vis,0,sizeof vis);
    		for(rg int i=1;i<n;++i)x=gi(),y=gi(),z=gi(),link(x,y,z),link(y,x,z);
    		Getrt(1,n);
    		ans=0;
    		solve(rt);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    

    cogs1863 聪聪可可:

    这个算出与根距离(mod 3)余数为0,1,2的各有多少个就好辣。

    // It is made by XZZ
    #include<cstdio>
    #include<algorithm>
    #define il inline
    #define rg register
    #define vd void
    #define sta static
    typedef long long ll;
    using namespace std;
    il int gi(){
    	rg int x=0,f=1;rg char ch=getchar();
    	while(ch<'0'||ch>'9')f=ch=='-'?-1:f,ch=getchar();
    	while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    	return x*f;
    }
    const int maxn=20001;
    int n,rt,fir[maxn],dis[maxn<<1],nxt[maxn<<1],w[maxn<<1],id,vis[maxn],siz[maxn],f[maxn],sum,dp[maxn];
    ll ans,dep[3];
    il vd link(const int&x,const int&y,const int&z){nxt[++id]=fir[x],fir[x]=id,dis[id]=y,w[id]=z;}
    il vd getrt(const int&x,const int&FA){
    	siz[x]=1;f[x]=0;
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(FA==dis[i]||vis[dis[i]])continue;
    		getrt(dis[i],x);
    		siz[x]+=siz[dis[i]];
    		f[x]=max(f[x],siz[dis[i]]);
    	}
    	f[x]=max(f[x],sum-siz[x]);
    	if(f[x]<f[rt])rt=x;
    }
    il vd Getrt(const int&x,const int&_sum){sum=_sum,f[0]=2e9,rt=0,getrt(x,-1);}
    il vd getdep(const int&x,const int&FA){
    	++dep[dp[x]%=3];
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(FA==dis[i]||vis[dis[i]])continue;
    		dp[dis[i]]=dp[x]+w[i];
    		getdep(dis[i],x);
    	}
    }
    il int cal(const int&x,const int&d){
    	dp[x]=d;dep[0]=dep[1]=dep[2]=0;getdep(x,-1);
    	return dep[0]*dep[0]+dep[1]*dep[2]*2;
    }
    il vd solve(const int&x){
    	vis[x]=1;ans+=cal(x,0);
    	for(rg int i=fir[x];i;i=nxt[i]){
    		if(vis[dis[i]])continue;
    		Getrt(dis[i],siz[dis[i]]);
    		ans-=cal(dis[i],w[i]);
    		solve(rt);
    	}
    }
    int main(){
    	n=gi();
    	int x,y,z;
    	for(rg int i=1;i<n;++i)x=gi(),y=gi(),z=gi(),link(x,y,z),link(y,x,z);
    	Getrt(1,n),solve(rt);
    	x=ans,y=n*n;while(y)z=y,y=x%y,x=z;
    	printf("%lld/%lld
    ",ans/x,(ll)n*n/x);
    	return 0;
    }
    

    没了。。我去学动态点分治了。。。

  • 相关阅读:
    CFree 提示main must return int
    策略模式
    CFree 提示no newline at the end of file
    EEPROM的写入操作解析
    一些关于mic的知识
    一些关于电池的资料
    太阳能电池板日发电量简易计算方法
    ubuntu 下载编译android源代码
    SC44B0的内存地址解析
    RequireJS 2.0 学习笔记一
  • 原文地址:https://www.cnblogs.com/xzz_233/p/8290131.html
Copyright © 2020-2023  润新知