zoukankan      html  css  js  c++  java
  • [POJ1741]Tree(点分治)

    树分治之点分治入门

    所谓点分治,就是对于树针对点的分治处理

    首先找出重心以保证时间复杂度

    然后递归处理所有子树

    对于这道题,对于点对(u,v)满足dis(u,v)<=k,分2种情况

    1. 路径过当前根
    2. 路径在子树中(递归处理)

    那么关键就是如何计算第一种情况

    设d[i]表示点i到当前根rt的距离,可以将d数组排序后线性复杂度求

    然而此时会有些点对是在同一棵子树中,这些情况要减去

    注意每次递归都要找一次重心以保证效率

    这样复杂度就是O(nlog2n)

    Code

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #define Inf 0x7fffffff
    #define N 10010
    using namespace std;
    
    struct info{int to,nex,w;}e[N*2];
    int n,k,tot,head[N],d[N],rt,Ans,sum,f[N],sz[N],dep[N];
    bool vis[N];
    
    void Link(int u,int v,int w){
    	e[++tot].nex=head[u];head[u]=tot;e[tot].to=v;e[tot].w=w;
    }
    
    inline 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;
    }
    
    void getrt(int u,int fa){
    	sz[u]=1,f[u]=0;
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==fa||vis[v]) continue;
    		getrt(v,u);
    		sz[u]+=sz[v];
    		f[u]=max(f[u],sz[v]);
    	}
    	f[u]=max(f[u],sum-sz[u]);
    	if(f[rt]>f[u]) rt=u;
    }
    
    void Init(){
    	tot=0,rt=0,Ans=0; 
    	memset(head,0,sizeof(head));
    	memset(vis,0,sizeof(vis));
    	for(int i=1;i<n;++i){
    		int u=read(),v=read(),w=read();
    		Link(u,v,w),Link(v,u,w);
    	}
    	sum=n,f[0]=Inf;
    	getrt(1,0);
    }
    
    void getdep(int u,int fa){
    	dep[++dep[0]]=d[u];
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(v==fa||vis[v]) continue;
    		d[v]=d[u]+e[i].w;
    		getdep(v,u);
    	}
    }
    
    int cal(int u,int cur){
    	d[u]=cur,dep[0]=0;
    	getdep(u,0);
    	sort(dep+1,dep+dep[0]+1);
    	int t=0;
    	for(int l=1,r=dep[0];l<r;)
    		if(dep[l]+dep[r]<=k) t+=r-l,++l;
    		else --r;
    	return t;
    }
    
    void solve(int u){
    	Ans+=cal(u,0);
    	vis[u]=1;
    	for(int i=head[u];i;i=e[i].nex){
    		int v=e[i].to;
    		if(vis[v]) continue;
    		Ans-=cal(v,e[i].w);
    		sum=sz[v];
    		getrt(v,rt=0);
    		solve(rt);
    	}
    } 
    
    int main(){
    	while(~scanf("%d%d",&n,&k)&&n){
    		Init();
    		solve(rt);
    		printf("%d
    ",Ans);
    	}
    }
    
  • 相关阅读:
    个人记录--当前年月,求当月天数和上月
    java修改图片大小
    多层iframe的页面取子标签
    oracle的游标
    json中获取key值
    iOS开发常用代码块(2)
    大话数据结构(六)——链式存储
    项目中比较有用得到js经验
    微信公众号开发——php sdk php中curl用法
    微信页面设计weui源代码(4)——Pciker微信页面中实现下拉菜单
  • 原文地址:https://www.cnblogs.com/void-f/p/9102070.html
Copyright © 2011-2022 走看看