POJ 1741 点分治

方法:指针扫描数组

每次选择树的重心作为树根,从树根出发进行一次DFS,求出点到树根的距离,把节点按照与树根的的距离放进数组d,设置两个指针L,R分别从前、后开始扫描,每次满足条件时答案累加R-L。,之后减去子树的满足条件的情况,删除根节点,对其子树继续上述操作,不断累加答案。

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int maxn=100010;
vector<pair<int,int> >G[maxn];
int d[maxn],size[maxn],root,max_w,n1,cnt,n,k;
bool vis[maxn];
void get_root(int x,int f){//求树的重心
	size[x]=1;
	int max_part=0;
	for(int i=0;i<G[x].size();i++){
		int Next=G[x][i].first;
		if(Next!=f&&!vis[Next]){
			get_root(Next,x);
			size[x]+=size[Next];
			max_part=max(max_part,size[Next]);
		}
	}
	max_part=max(max_part,n1-size[x]);
	if(max_part<max_w){
		root=x;
		max_w=max_part;
	}
}
void get_dist(int x,int f,int dist){//算距离
	d[++cnt]=dist;
	size[x]=1;//算距离的同时也更新一下子树的大小
	for(int i=0;i<G[x].size();i++){
		int Next=G[x][i].first;
		if(Next!=f&&!vis[Next]){
			get_dist(Next,x,dist+G[x][i].second);
			size[x]+=size[Next];
		}
	}
}
int cal(int x,int y){//计算
	cnt=0;
	get_dist(x,-1,y);
	sort(d+1,d+1+cnt);
	int ans=0;
	for(int i=1,j=cnt;i<j;i++){
		while(d[i]+d[j]>k&&i<j)j--;
		ans+=j-i;
	}
	return ans;
}
int dfs(int x){//dfs主框架
	max_w=n1;
	get_root(x,-1);
	int now=root;
	vis[now]=1;
	int ans=0;
	ans+=cal(now,0);
	for(int i=0;i<G[now].size();i++){
		int Next=G[now][i].first;
		if(!vis[Next]){
			ans-=cal(Next,G[now][i].second);
			n1=size[Next];
			ans+=dfs(Next);
		}
	}
	return ans;
}
void init(int n){
	for(int i=1;i<=n;i++)G[i].clear();
	cnt=0;
	memset(vis,0,sizeof(vis));
}
int main(){
	int u,v,dis;
	while(~scanf("%d%d",&n,&k)&&n&&k){
		init(n);
		for(int i=1;i<n;i++){
			scanf("%d%d%d",&u,&v,&dis);
			G[u].push_back(make_pair(v,dis));
			G[v].push_back(make_pair(u,dis));
		}
		n1=n;
		printf("%d\n",dfs(1));
	}
}
//5 1
//1 2 1
//2 3 1
//3 4 1
//4 5 1

原文地址:https://www.cnblogs.com/pkgunboat/p/9709941.html

时间: 2024-10-25 10:05:27

POJ 1741 点分治的相关文章

POJ 1741 树分治(点分治模板题)

POJ 1741 题意:求一棵树中点对<=k的数量. 总结:点分治,搞不太懂..大概敲了一遍 #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stac

POJ 1741 树分治

题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典的树分治的题.假设我们选择了一个参考点u,那么对于不同的点对(u,v),(u , v)之间的路径有两种情况,经过点u,和不经过点u,加入我算出了没有经过点u的对数,然后把经过点u的加起来就是答案了,很简单,这就是分治的思想.具体看代码. #include<cstdio> #include<c

POJ 1741 Tree (树上点分治)(楼教主男人八题之一)

题目地址:POJ 1741 树分治第一发! 树分治详情请看漆子超的国家集训队论文,论文传送门 树分治裸题. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #

【POJ 1741】 Tree (树的点分治)

Tree Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v)

【点分治】【POJ 1741】【cogs 1714】树上的点对

1714. [POJ1741][男人八题]树上的点对 ★★★ 输入文件:poj1741_tree.in 输出文件:poj1741_tree.out 简单对比 时间限制:1 s 内存限制:256 MB [题目描述] 给一棵有n个节点的树,每条边都有一个长度(小于1001的正整数). 定义dist(u,v)=节点u到节点v的最短路距离. 给出一个整数k,我们称顶点对(u,v)是合法的当且仅当dist(u,v)不大于k. 写一个程序,对于给定的树,计算有多少对顶点对是合法的. [输入格式] 输入包含多

poj 1741 树的点分治(入门)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 18205   Accepted: 5951 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an

树的点分治 (poj 1741, 1655(树形dp))

poj 1655:http://poj.org/problem?id=1655 题意: 给无根树,  找出以一节点为根,  使节点最多的树,节点最少. 题解:一道树形dp,先dfs 标记 所有节点的子树的节点数. 再dfs  找出以某节点为根的最大子树,节点最少. 复杂度(n) /***Good Luck***/ #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <cstdio> #include <cs

点分治——POJ 1741

写的第一道点分治的题目,权当认识点分治了. 点分治,就是对每条过某个点的路径进行考虑,若路径不经过此点,则可以对其子树进行考虑. 具体可以看menci的blog:点分治 来看一道例题:POJ 1741 Tree 题目大意:扔给你一颗有权无根树,求有多少条路径的长度小于k: 解题思路:先找出重心,用一次dfs处理出每个点到根的距离dis,然后将dis[]排序,用O(n)的复杂度处理出"过根且长度小于等于k的路径数目",删除根节点,对于每棵子树重复上述操作. 注意要去重: 像上面这样一个图

poj 1741 楼教主男人八题之一:树分治

http://poj.org/problem?id=1741 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001). Define dist(u,v)=The min distance between node u and v. Give an integer k,for every pair (u,v) of vertices is called valid