首页 > 其他分享 >树分治

树分治

时间:2024-10-11 10:13:45浏览次数:9  
标签:rt sz edg int 分治 maxi

点分树

关于模拟赛 \(T2\) 考点分树这件事。

点分治

点分树被称为动态点分治,所以下面先介绍点分治。

P3806 【模板】点分治 1

点分治板子。考虑一个树上的路径,如果已知所有 \(dis,\) 可以按是否经过根划分为:

  1. 经过根:\(dis[u]+dis[v],\) 这个方便用桶处理。
  2. 没有经过根:经过了根的子树的根,分治处理根的子树。这也就是点分治。

所以只需要慢慢分治就好了。但是你会发现这样做的复杂度是 \(\mathcal{O(n^2)}\) 的,不可接受。所以考虑优化。

注意到每次的递归数量取决于子树大小,为了让每个子树都很小,可以考虑将重心作为子树的根。

每一次分治的时候分治子树重心就好了。

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+10,inf=1e7,maxn=1e7+10;
int edg,fir[N],nxt[N],to[N],w[N],que[N],sz[N],maxi[N],dis[N],ans[N];
int n,m,rt,top,cnt,sum,stk[N],dd[N];
bitset<maxn>vis,tf;
inline void add(int x,int y,int z){	nxt[++edg]=fir[x],fir[x]=edg,to[edg]=y,w[edg]=z; }
void dfs1(int u,int f){
	sz[u]=1,maxi[u]=0;
	for(int t=fir[u];t;t=nxt[t]){
		int v=to[t];
		if(v^f&&!vis[v])dfs1(v,u),sz[u]+=sz[v],maxi[u]=max(maxi[u],sz[v]);
	}
	maxi[u]=max(maxi[u],sum-sz[u]);
	rt=(maxi[u]<maxi[rt]?u:rt);
}
void dfs2(int u,int f){
	dd[++cnt]=dis[u];
	for(int t=fir[u];t;t=nxt[t]){
		int v=to[t];
		if(v^f&&!vis[v])dis[v]=dis[u]+w[t],dfs2(v,u);
	}
	return;
}
void dfz(int u,int f){
	vis[u]=true,stk[++top]=0,tf[0]=true;
	for(int t=fir[u];t;t=nxt[t]){
		int v=to[t];
		if(v^f&&!vis[v]){
			dis[v]=w[t];
			dfs2(v,u);
			dis[v]=w[t],dfs2(v,u);
			for(int k=1;k<=cnt;++k)for(int i=1;i<=m;++i)if(que[i]>=dd[k])ans[i]|=tf[que[i]-dd[k]];
			for(int k=1;k<=cnt;++k)if(dd[k]<inf)stk[++top]=dd[k],tf[dd[k]]=true;
			cnt=0;
		}
	}
	while(top)tf[stk[top--]]=0;
	for(int t=fir[u];t;t=nxt[t]){
		int v=to[t];
		if(!vis[v]&&v^f)sum=sz[v],rt=0,maxi[rt]=inf,dfs1(v,u),dfz(rt,u);
	}
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>n>>m;
	for(int i=1,x,y,z;i<n;++i)cin>>x>>y>>z,add(x,y,z),add(y,x,z);
	for(int i=1;i<=m;++i)cin>>que[i];
	maxi[rt]=inf,sum=n,rt=0,dfs1(1,-1),dfz(rt,-1);
	for(int i=1;i<=m;++i)if(ans[i])cout<<"AYE\n";else cout<<"NAY\n";
	return 0;
}

P4178 Tree

和上一道题大致相同,注意到复杂度瓶颈在于统计 \(tf.\) 考虑到 \(tf\) 的计算区间是连续的 ,使用一个树状数组维护之。

标签:rt,sz,edg,int,分治,maxi
From: https://www.cnblogs.com/chihirofujisaki/p/18457864/dfz

相关文章

  • 点分治
    感觉非常有深度,感觉过几天就又要忘了,所以我写个题解。P3806【模板】点分治1给定一棵有\(n\)个点的树,询问树上距离为\(k\)的点对是否存在。题意非常简单题意越短越毒瘤。大佬原文我们先想想点对有几种情况:第一种是经过根节点的路径;第二种是不经过根节点的路径;想第一......
  • 分治法
    算法导论这个文档是学习“算法设计与分析”课程时做的笔记,文档中包含的内容包括课堂上的一些比较重要的知识、例题以及课后作业的题解。主要的参考资料是Introductiontoalgorithms-3rd(ThomasH.)(对应的中文版《算法导论第三版》),除了这本书,还有的参考资料就是Algorithmsdesi......
  • 【模板】"动态DP"&动态树分治
    目录题目描述朴素算法矩阵刻画实现code以洛谷模板题为例介绍动态dp的一般方法。P4719【模板】"动态DP"&动态树分治-洛谷|计算机科学教育新生态(luogu.com.cn)P4751【模板】"动态DP"&动态树分治(加强版)-洛谷|计算机科学教育新生态(luogu.com.cn)题目描述给定一......
  • CDQ分治
    前置知识 归并排序(一维偏序) 推荐写法:https://www.cnblogs.com/didiao233/p/17986130第1题   归并排序 查看测评数据信息给定你一个长度为n的整数数列。请你使用归并排序对这个数列按照从小到大进行排序。并将排好序的数列按顺序输出。输入格式 输入共......
  • 洛谷题单指南-分治与倍增-P6648 [CCC2019] Triangle: The Data Structure
    原题链接:https://www.luogu.com.cn/problem/P6648题意解读:在一个n行的数字三角形中,求所有边长为k的正三角形最大值之和。解题思路:1、枚举法枚举每一个边长为k的三角形,在其中求max,然后累加,n最多3000,时间复杂度是n^4,显然超时。2、倍增和ST思想此题非常类似于RMQ问题,也就是求区......
  • [2023四校联考3]sakuya 题解(根号分治)
    题目链接。题目分析第一个操作类似哈希冲突那一道题,可以运用类似的思路开一个二维表,很容易想到两种做法:开一个二维表,表上的第\(i\)行,第\(j\)列表示序列下标在模\(i\)意义下等于\(j\)的加法标记。对于修改操作,直接暴力修改对应的那一行的值即可,查询时用线段树查询那个......
  • 99th 2024/9/4 CDQ分治小结
    概括轻新小思路用于处理点对关系题在能将点对分段处理(如下)的题目中有奇效试想,现在要处理部分点对,其范围为\(l\in[L,R],r\in[L,R]\)其位置不确定,但是我们可以考虑将其分为三个板块分别作出的总贡献即分为\(l\in[L,mid],r\in[mid+1,R]\)\(l\in[L,mid],r\in[L,mid]\)\(l......
  • CDQ分治学习笔记
    CDQ分治学习笔记k维偏序问题求满足条件的二元组个数题意描述每个元素有\(k\)个值,要求满足(以\(k=2\)为例)\(a_j\lea_i,b_j\leb_i\)的点对个数。分析这实际上就是我们熟悉的逆序对问题,回忆一下我们是怎么处理的,首先来说,当\(a,b\)其中一个的含义是下标的时候可以直......
  • 树分治
    点分治点分治适合处理大规模的树上路径信息问题。本质思想是选择一点作为分治中心,将原问题划分为几个相同的子树上的问题,进行递归解决。常见的用于统计树上有关路径的信息。假设当前选定根节点为\(rt\),则符合条件的路径必然是以下两种之一:经过\(rt\)或一段在\(rt\)上;在......
  • 揭秘合并排序:分治排序初学者指南
    归并排序由约翰·冯·诺依曼于1945年提出,主要是为了提高大型数据集的排序效率。冯·诺依曼的算法旨在使用分而治之的方法提供一致且可预测的排序过程。这种策略允许归并排序有效地处理小型和大型数据集,保证在所有情况下都能实现稳定的排序,时间复杂度为o(nlogn)。合并排序采用......