首页 > 其他分享 >点分治

点分治

时间:2023-08-06 17:11:25浏览次数:42  
标签:rt sz int 分治 Find vis mx


点分治模板1

注意 vis 数组的作用 , 相当于把树切割
注意变量 sum 的作用 , 第一次写的时候没用 sum , 全部用了 n , 导致没有正确找到树的重心 , 然后 tle

#include <bits/stdc++.h>
using ll = long long;
const int N = 1E4 + 5 , M = 105 , O = 1E7 + 10;
const int INF = 1E9;

int n,m,rt,sum;
int sz[N],mx[N],d[N];
std::vector<std::array<int,3>> e[N];
int que[M],p[N],cnt;
bool U[O],vis[N],ans[M];
int q[N],l,r;

void Find_hs(int u,int pa) {
	
	sz[u] = 1 , mx[u] = 0;
	for (auto f : e[u]) {
		int v = f[0];
		if (v == pa || vis[v]) continue;
		Find_hs(v , u);
		sz[u] += sz[v];
		mx[u] = std::max(mx[u] , sz[v]);
	}	
	
	mx[u] = std::max(mx[u] , sum - sz[u]);
	if (mx[rt] > mx[u]) rt = u;
}
void Find_dist(int u,int pa) {
	
	p[++cnt] = d[u];
	for (auto f : e[u]) {
		int v = f[0] , w = f[1];
		if (v == pa || vis[v]) continue;
		d[v] = d[u] + w;
		Find_dist(v , u);
	}
	
}
void Dfz(int u , int pa) 
{
	vis[u] = 1 , U[0] = 1;
	l = 0 , r = -1;
	q[++r] = 0;
	
	for (auto f : e[u]) {
		
		int v = f[0] , w = f[1];
		if (v == pa || vis[v]) continue;
		
		cnt = 0;
		d[v] = w ; Find_dist(v , u);
		
		for (int i = 1 ; i <= m ; ++i) {
			for (int j = 1 ; j <= cnt ; ++j) {
				if (p[j] <= que[i]) ans[i] |= U[que[i] - p[j]];
			}
		}
		
		for (int j = 1 ; j <= cnt ; ++j) {
			if (p[j] >= O) continue;
			q[++r] = p[j] , U[p[j]] = 1;
		}
	}	
	
	//清空 U 数组 
	while (l<=r) U[q[l++]] = 0;
	
	for (auto f : e[u]) {
		int v = f[0] , w = f[1];
		if (v == pa || vis[v]) continue;
		mx[rt = 0] = INF; sum = sz[v]; 
		Find_hs(v , -1) , Find_hs(rt , -1);
		Dfz(rt , -1);
	}
	
}

int main() 
{
	std::ios::sync_with_stdio(false);
	std::cin.tie(nullptr);
	
	std::cin >> n >> m;
	for (int i = 1 ; i <= n - 1 ; ++i) {
		int u,v,w;
		std::cin >> u >> v >> w;
		e[u].push_back({v , w});
		e[v].push_back({u , w});
	}
	for (int i = 1 ; i <= m ; ++i) {
		std::cin >> que[i];
	}
	
	//注意每次的 sum 会变 
	mx[rt = 0] = INF , sum = n;
	Find_hs(1 , -1);
	Find_hs(rt , -1); //重新更新以 rt 为根的 sz 信息
	Dfz(rt , -1); 
	
	for (int i = 1 ; i <= m ; ++i) {
		if (ans[i]) std::cout << "AYE\n";
		else std::cout << "NAY\n";
	}
	
	return 0;	
}

标签:rt,sz,int,分治,Find,vis,mx
From: https://www.cnblogs.com/xqy2003/p/17609586.html

相关文章

  • [Ynoi2016] 这是我自己的发明(根号分治+分块/莫队)
    题目传送门soltion简单题换根显然可以拆成\(O(1)\)个区间,这里先不管。直接做法是莫队,把双子树拆成\(dfs\)序上的双前缀,可以直接莫队,但是常数比较大。另一种做法是根分,对颜色出现次数分治,大于的求出\(dfs\)序的前缀和即可,小于的因为一共只有\(O(n\sqrtn)\)个点对,所以......
  • C/C++ 数据结构五大核心算法之分治法
    分治法——见名思义,即分而治之,从而得到我们想要的最终结果。分治法的思想是将一个规模为N的问题分解为k个较小的子问题,这些子问题遵循的处理方式就是互相独立且与原问题相同。两部分组成:分(divide):递归解决较小的问题治(conquer):然后从子问题的解构建原问题的解三个步骤:1、......
  • 面试-基本的算法要了如指掌,比如查找、排序、动态规划、分治等
    在了解这些基本算法之前还是得先了解这些基本的数据结构,这些都是要熟记与心的。基本数据结构比如:字符串、链表、二叉树、堆、栈、队列、哈希等字符串stringstr="helloworld";//使用格式//string是类。//str输出的大小,取决于size函数的返回值。链表classListNode{ pu......
  • luogu P3733 [HAOI2017] 八纵八横 题解【线段树分治+线性基+可撤销并查集+bitset】
    目录题目大意解题思路code题目大意题目链接给出一张\(n\)个点\(m\)条边的连通无向图,边带边权\(w_i\)。有以下三种操作,共\(q\)次:\(\centerdot\)在点\(x,y\)之间加入一条边权为\(w_i\)的边,如果这是第\(i\)个此种操作,则记这条新边为第\(i\)条。\(\centerdot\)将第\(k......
  • CDQ分治【使用说明书】
    适用范围cdq分治,用于解决各类动态(包含修改操作)的离线问题,在此方面可以用于替代复杂的数据结构,实现更简单的解法。对口的问题通常由一些修改和查询操作组成。注:本产品老少咸宜,患有高血压、低血糖者均可使用。本产品口服、外敷均可,推荐搭配c++食用,口感更佳。生效原理这玩......
  • cdq分治
    cdq分治是用分治来解决偏序(多是三维偏序)问题其实我也不知道具体解决什么这里就先以P3870陌上花开【三维偏序】为例要求的就是\(\sum_{i=0}^{n}\)中\(a_i<a_j\)且\(b_i<b_j\)且\(c_i<c_j\)且\(i\not=j\)的个数这里就是典型的三维偏序那思路肯定都是先找\(a_i<a_j\),再找\(b_i......
  • 20230626-树链剖分+点分治
    20230626重链剖分计算每个节点子树大小,判断出每个点的重儿子优先遍历重儿子连边,并且按照DFS序重新编号特点:每条重链上的点编号是连续的每个点为根的子树内所有点的编号是连续的$\to$线段树需求:对于树上两点\(x,y\)路径上的所有点进行操作必然不能避免的事情......
  • 点分治 - 知识点梳理
    分治是一种将大的问题拆分成更小的问题并分而治之的算法,有利于使一个大的问题迅速缩小。在线性区间上的分治一般从区间中点将区间一分为二(这个中点也叫做分治中心),这样分\(\logn\)次就能使区间大小缩小到\(1\)。而在树上的分治一般以树的重心作为分治中心,这样分\(\logn\)次......
  • 分治法处理大整数相乘问题
    分治法解决大整数相乘问题1.题目描述大数乘法法运算跟一般的减法运算是不同的,在面对基本数据类型容量有限而导致无法存储特大数字的情况下,本文采用分治策略的方法来解决大数减运算问题。输入:两个代表整数的字符串a和b,规定a>=b,a,b>0。输出:返回表示结果整数的字符串。2.解决......
  • 线段树分治结构
    目录线段树分治结构基本知识:例题1: 模板(基础题)例题2: dp(背包)(会了就掌握题)线段树分治结构基本知识:应用点: 当有些东西一会出现,一会又不出现时,可以使用线段树分治方式: 维护某一个东西出现的时间段,并在线段树上打上标记,并dfs遇到标记后,就相当于加入了这个物品。当dfs到叶子节点后,就......