P4178&POJ1741 Tree 点分治模板题

在这里插入图片描述
点分治算法是一种对树上路径统计极其有效的算法。在要求求解树上路径等方面的问题时,我们可以思考能否用点分治解决。
分治是将一个问题拆解成几个子问题的递归解决问题的方法,而在树上的分治受到了树的形状的影响。

在这里插入图片描述
我们看到,加入根节点选取的不合适,造成一棵树的深度过于的大,那么时间复杂度也是极高的,因此我们需要选取合适的点,使得最大子树的最小。而满足这个条件的点我们称之为树的重心,其可以通过一个dfs来获得

int get_root(int u,int fa)//找出树的重心
{//siz[i]是指以i为根子树的大小,maxson[i]是指以i为根最大的子树的大小
	//SIZE 为当前处理的这棵树的大小 maxx代表已经找到的最大子树的最小值
	siz[u] = 1;maxson[u] = 0;
	for(int i = head[u];i != 0;i = edge[i].next){
		int v = edge[i].to;
		if(vis[v] || v == fa) continue;
		get_root(v,u);
		siz[u] = siz[u] + siz[v];
		maxson[u] = max(maxson[u],siz[v]);
	}
	maxson[u] = max(maxson[u],SIZE-siz[u]);
	if(maxson[u] < maxx) root = u,maxx = maxson[u];
}

相应的我们也要获得,以当前节点为根节点的子树上的各节点到根节点的距离值

void get_dis(int u,int fa,int d)//从每一棵新建的子树求距离函数
{
	dis[++num] = d;//d数组保存当前根节点到每一个点的距离
	for(int i = head[u];i;i = edge[i].next){
		int v = edge[i].to;
		if(vis[v] || v == fa) continue;
		get_dis(v,u,d+edge[i].w);
	}
	return ;
}

接下来就是最为核心的函数了。因为这个题目中我们一开始直接对根节点就行统计时,会有重复的统计,所以我们在接下来的统计中需要消除这些重复的部分。所以solve函数len的数值是会变化的,对dis数组排一个序这样利用双指针的方法,可以求解出有多少对路径满足这个条件。
可以看到,在分治的函数中,初始solve的len不同,因为我们从子树的根节点出发,所以我们需要把根节点到子树根节点的这段距离加上来统计答案

int calculate(int rt,int len)
{
	num = 0;
	memset(dis,0,sizeof(dis));
	get_dis(rt,0,len);//以当前子树的根节点出发 获得一下路径长度
	sort(dis+1,dis+1+num);
	int L = 1,R = num,res = 0;
	while(L <= R){//双指针法 确定答案
		if(dis[L] + dis[R] <= k){
			res += R-L;+
			L++;
		}
		else R--;
	}
	return res;
}

void Divide(int rt)//分治函数 核心部分
{
	ans = ans + calculate(rt,0);
	vis[rt] = 1;
	for(int i = head[rt];i;i = edge[i].next){//对没棵子树进行分治
		int v = edge[i].to;
		if(vis[v]) continue;
		ans = ans - calculate(v,edge[i].w);
		SIZE = siz[v];//都重新换一下 以下的信息全部重新赋一个值
		maxx = inf;
		root = 0;
		get_root(v,rt);
		Divide(root);//分治新的根节点
	}
	return ;
}

一般来说,点分治的题目找重心,算距离,分治求解这三个函数具体内容是差不多,关键的还是solve函数(计算函数),根据题目而不同,需要具体分析

完整代码:


Problem: 1741		User: tzteyang777
Memory: 1316K		Time: 844MS
Language: G++		Result: Accepted
Source Code
//#include <bits/stdc++.h>
#include <cstring>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <cstdio>

using namespace std;
typedef long long ll;
//点分治
//找到一个节点使其最大子树的大小尽量小 这时分治递归的时间复杂度是最低的
//而这样的节点 就叫做树的重心 可以用一个dfs来求O(n)的时间
const int MAXN = 1e4+7;
#define inf 0x3f3f3f3f
int head[MAXN],maxson[MAXN],vis[MAXN],siz[MAXN],dis[MAXN];
int cnt,SIZE,maxx,num,k,root;
ll ans;
struct Edge
{
	int to,next,w;
}edge[MAXN<<1];

void addedge(int u,int v,int w)
{
	edge[++cnt].to = v;
	edge[cnt].w = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
}

int get_root(int u,int fa)//找出树的重心
{//siz[i]是指以i为根子树的大小,maxson[i]是指以i为根最大的子树的大小
	//SIZE 为当前处理的这棵树的大小 maxx代表已经找到的最大子树的最小值
	siz[u] = 1;maxson[u] = 0;
	for(int i = head[u];i != 0;i = edge[i].next){
		int v = edge[i].to;
		if(vis[v] || v == fa) continue;
		get_root(v,u);
		siz[u] = siz[u] + siz[v];
		maxson[u] = max(maxson[u],siz[v]);
	}
	maxson[u] = max(maxson[u],SIZE-siz[u]);
	if(maxson[u] < maxx) root = u,maxx = maxson[u];
}

void get_dis(int u,int fa,int d)//从每一棵新建的子树求距离函数
{
	dis[++num] = d;//d数组保存当前根节点到每一个点的距离
	for(int i = head[u];i;i = edge[i].next){
		int v = edge[i].to;
		if(vis[v] || v == fa) continue;
		get_dis(v,u,d+edge[i].w);
	}
	return ;
}

int calculate(int rt,int len)
{
	num = 0;
	memset(dis,0,sizeof(dis));
	get_dis(rt,0,len);
	sort(dis+1,dis+1+num);
	int L = 1,R = num,res = 0;
	while(L <= R){//双指针法 确定答案
		if(dis[L] + dis[R] <= k){
			res += R-L;+
			L++;
		}
		else R--;
	}
	return res;
}

void Divide(int rt)//分治函数 核心部分
{
	ans = ans + calculate(rt,0);
	vis[rt] = 1;
	for(int i = head[rt];i;i = edge[i].next){//对没棵子树进行分治
		int v = edge[i].to;
		if(vis[v]) continue;
		ans = ans - calculate(v,edge[i].w);
		SIZE = siz[v];//都重新换一下
		maxx = inf;
		root = 0;
		get_root(v,rt);
		Divide(root);//分治新的根节点
	}
	return ;
}

int main()
{
	int n;
	while(~scanf("%d%d",&n,&k)&&(n&&k)){
		cnt = 0;
		memset(head,0,sizeof(head));
		for(int i = 1;i < n;i ++){
			int a,b,c;
			scanf("%d%d%d",&a,&b,&c);
			addedge(a,b,c);
			addedge(b,a,c);
		}
		ans = 0;
		memset(vis,0,sizeof(vis));
		maxx = inf;SIZE = n;
		get_root(1,0);
		Divide(root);
		printf("%lld\n",ans);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ava实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),可运行高分资源 Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现的毕业设计&&课程设计(包含运行文档+数据库+前后端代码),Java实现
C语言是一种广泛使用的编程语言,它具有高效、灵活、可移植性强等特,被广泛应用于操作系统、嵌入式系统、数据库、编译器等领域的开发。C语言的基本语法包括变量、数据类型、运算符、控制结构(如if语句、循环语句等)、函数、指针等。下面详细介绍C语言的基本概念和语法。 1. 变量和数据类型 在C语言中,变量用于存储数据,数据类型用于定义变量的类型和范围。C语言支持多种数据类型,包括基本数据类型(如int、float、char等)和复合数据类型(如结构体、联合等)。 2. 运算符 C语言中常用的运算符包括算术运算符(如+、、、/等)、关系运算符(如==、!=、、=、<、<=等)、逻辑运算符(如&&、||、!等)。此外,还有位运算符(如&、|、^等)和指针运算符(如、等)。 3. 控制结构 C语言中常用的控制结构包括if语句、循环语句(如for、while等)和switch语句。通过这些控制结构,可以实现程序的分支、循环和多路选择等功能。 4. 函数 函数是C语言中用于封装代码的单元,可以实现代码的复用和模块化。C语言中定义函数使用关键字“void”或返回值类型(如int、float等),并通过“{”和“}”括起来的代码块来实现函数的功能。 5. 指针 指针是C语言中用于存储变量地址的变量。通过指针,可以实现对内存的间接访问和修改。C语言中定义指针使用星号()符号,指向数组、字符串和结构体等数据结构时,还需要注意数组名和字符串常量的特殊性质。 6. 数组和字符串 数组是C语言中用于存储同类型数据的结构,可以通过索引访问和修改数组中的元素。字符串是C语言中用于存储文本数据的特殊类型,通常以字符串常量的形式出现,用双引号("...")括起来,末尾自动添加'\0'字符。 7. 结构体和联合 结构体和联合是C语言中用于存储不同类型数据的复合数据类型。结构体由多个成员组成,每个成员可以是不同的数据类型;联合由多个变量组成,它们共用同一块内存空间。通过结构体和联合,可以实现数据的封装和抽象。 8. 文件操作 C语言中通过文件操作函数(如fopen、fclose、fread、fwrite等)实现对文件的读写操作。文件操作函数通常返回文件指针,用于表示打开的文件。通过文件指针,可以进行文件的定位、读写等操作。 总之,C语言是一种功能强大、灵活高效的编程语言,广泛应用于各种领域。掌握C语言的基本语法和数据结构,可以为编程学习和实践打下坚实的基础。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值