• 点分治


    点分治

    给定一棵带权树,求树上路径小于等于k,求简单路径条数,不可以有重边;
    显然,对于每个点来说,有两种情况
    1,过这个点的路径;
    2,不过这个点的路径;
    对于第二种情况,显然会经过其他节点,为了避免算重,每次算完之后把当前点删去;
    为了使删完后的树尽量平衡,可以选择重心;
    对于1这种情况,以选出来的重心为根节点,遍历一遍树;
    算出其他点到root的距离d[i],从小到大排序,用双指针;
    左端点枚举l,右端点不断向左移,每次答案加上r-l,因为l自己本身不算;
    由于题目要求简单路径,所以如果其中有两个点在同一个子树中,不符合情况;
    可以用容斥解决,可以单独算在每个子树的情况,用总答案减去即可;
    对于第二种情况,遍历删去当前节点的每一个棵子树,重复1过程;

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N=4e4+7;
    const int inf=0x3f3f3f3f; 
    struct edge{
    	int v,w,nxt;
    }e[N<<1];
    int n,k,now_siz,sz,root,ans,cnt,tot;
    int head[N],d[N],st[N],siz[N],vis[N];
    void add_edge(int u,int v,int w){
    	e[++cnt]=(edge){v,w,head[u]};
    	head[u]=cnt;
    }
    void get_root(int u,int fa){
    	siz[u]=1;
    	int res=0;
    	for(int i=head[u];i;i=e[i].nxt){
    		int to=e[i].v;
    		if(vis[to]||to==fa) continue;
    		get_root(to,u);
    		siz[u]+=siz[to];
    		res=max(res,siz[to]);
    	}
    	res=max(res,sz-siz[u]);
    	if(res<now_siz) root=u,now_siz=res;
    }
    void get_dis(int u,int fa){
    	st[++tot]=d[u];
    	for(int i=head[u];i;i=e[i].nxt){
    		int to=e[i].v;
    		if(vis[to]||to==fa) continue;
    		d[to]=d[u]+e[i].w;
    		get_dis(to,u);
    	}
    }
    int solve(int u,int dis){
    	d[u]=dis;
    	tot=0;
    	get_dis(u,0);
    	sort(st+1,st+tot+1);
    //	for(int i = 1;i <= tot; i++) cout << st[i] << " ";
    //	cout <<endl;
    	int l=1,r=tot,res=0;
    	for(;l<r;l++){
    		while(st[r]+st[l]>k){
    			r--;
    		}
    		if(l<r) res+=r-l;
    	}
    //	cout<<res<<"
    ";
    	return res;
    	
    }
    void dfs(int u){
    	vis[u]=1;
    //	cout<<"-->"<<u<<"
    ";
    	ans+=solve(u,0);
    	for(int i=head[u];i;i=e[i].nxt){
    		int to=e[i].v;
    		if(vis[to]) continue;
    		ans-=solve(to,e[i].w);
    		now_siz=inf,sz=siz[to],root=0;
    		get_root(to,0);
    		dfs(root);
    	}
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<n;i++){
    		int x,y,z;
    		scanf("%d%d%d",&x,&y,&z);
    		add_edge(x,y,z);
    		add_edge(y,x,z);
    	}
    	scanf("%d",&k);
    	now_siz=inf,sz=n,root=0;
    	get_root(1,0);
    	dfs(root);
    	cout<<ans;
    }
    
  • 相关阅读:
    ubuntu下android开发工作环境搭建
    ADB命令行控制界面开关
    chromium os系统编译与环境搭建
    完整代理的简单实现
    OC协议、代理的简单使用
    OC字典的使用
    OC数组的简单使用、NSArray
    OC中NSString的使用、字符串的使用
    OC内存管理、非ARC机制、MRR机制
    OC中重写set和get方法、懒加载
  • 原文地址:https://www.cnblogs.com/Aswert/p/13599750.html
Copyright © 2020-2023  润新知