首页 > 其他分享 >点分治学习笔记

点分治学习笔记

时间:2022-10-31 21:12:48浏览次数:75  
标签:tmp sz int 分治 T2 笔记 学习 now

点分治

点分治用于求解树上路径有关的问题。

其具体思想,对于当前处理的这一个分治区域,我们计算所有区域内跨过分治中心这一个点的所有路径的贡献,然后将分治中心及与其相邻的边删去,对于剩下的每一个分治区域再分别进行计算。

时间复杂度

看起来很暴力,实际上非常优秀,其关键就是我们对于分治中心的选取。一般而言,我们选择这一分治区域的重心

选择重心的原因是,删去重心后,剩下的没一个区域内的点数至少减半,这样的话,最多只会递归 \(\log n\) 次,时间复杂度就是每一层处理的时间复杂度乘上 \(\log n\) 。

具体做法

模板题 P4178 Tree

询问树上两点距离小于等于 \(k\) 的点对数量。

对于当前处理的分治区域,从分治中心开始进行 \(dfs\) ,处理出每个结点到达中心的距离,并排序,然后双指针扫过去就可以了。

  • 这样处理会有一个问题:有一些不合法的情况也会被计算在内。

如下图

因此我们考虑减去这样的不合法的情况,我们发现不合法是由于两个端点来自于同一个儿子,那么我们对于中心的每一个儿子,减去其所造成的不合法的贡献即可。

点击查看代码
inline void Getroot(int x,int f) {
	sz[x]=1;
	int now=0;
	for(int i=hd[x],y;i;i=ne[i]) 
		if(!vis[y=to[i]] && y!=f) 
			Getroot(y,x), sz[x]+=sz[y], now=max(now,sz[y]);
	now=max(now,all-sz[x]);
	if(now<Mx) Mx=now, Rt=x;
}

inline void Getdist(int x,int f,int dist) {
	sz[x]=1; tmp[++cnt]=dist;
	mx[Rt]=max(mx[Rt],dist);
	dis[x][cnt[x]]=dist; cnt[x]++;
	for(int i=hd[x],y;i;i=ne[i]) 
		if(!vis[y=to[i]] && y!=f) Getdist(y,x,dist+1), sz[x]+=sz[y];
}

inline void Solve(int x) {
	vis[x]=1;
	for(int i=hd[x],y;i;i=ne[i]) if(!vis[y=to[i]]) {
		Mx=inf; all=sz[y]; Getroot(y,0); 
		Getdist(Rt,0,0); New(Rt,mx[Rt],mx[x]);
		Fa[Rt]=x; Solve(Rt);
	}
}
inline int calc(int x,int dist0) {
    cnt=0; 
    Getdist(x,dist0);
    sort(tmp+1,tmp+1+cnt);
    int l=1,r=cnt,res=0;
    while(l<r) 
        if(tmp[l]+tmp[r]<=k) ret+=r-l, l++;
        else r--;
    return res;
}

点分树

点分树就是将每一个分治中心,向它所在区域内的下一级分治中心连边,由于每次选取的分治中心是重心,那么树高不会超过 \(\log n\) ,这样我们每一次就可以暴力在树上进行查询和修改等操作。

具体的,对于每一个结点,维护两个信息:

T1[x] // 点分树上 x 子树内的点到 x 的距离
T2[x] // 点分树上 x 子树内的点到 Fa[x] 的距离
// Fa[x] 是 x 在点分树上的父亲结点
// 一般的,将距离做下标
  • 查询操作

对于 \(p\) 到 \(Rt\) 路径上的点 \(u\),上一次查询的点为 \(las\)

查询 \(T1[x]\) 内区间 \([0-(k-Dis[p][x])]\) 的贡献并加上。

查询 \(T2[las]\) 内区间 \([0-(k-Dis[p][x])]\) 的贡献并减去,因为这样的路径是不合法的。

  • 修该操作

对于 \(p\) 到 \(Rt\) 路径上的点 \(u\)

在 \(T1[x]\) 中下标为 \(Dis[p][x]\) 的位置加上 \(v-a[p]\)

在 \(T2[x]\) 中下标为 \(Dis[p][Fa[x]]\) 的位置加上 \(v-a[p]\)。

开 \(vector\) 用树状数组维护即可。

模板题P6329 【模板】点分树 | 震波

点击查看代码
inline void New(int x,int v1,int v2) { T1.tree[x].resize(v1+2); T2.tree[x].resize(v2+2); }

inline void Getroot(int x,int f) {
	sz[x]=1;
	int now=0;
	for(int i=hd[x],y;i;i=ne[i]) 
		if(!vis[y=to[i]] && y!=f) 
			Getroot(y,x), sz[x]+=sz[y], now=max(now,sz[y]);
	now=max(now,all-sz[x]);
	if(now<Mx) Mx=now, Rt=x;
}

inline void Getdist(int x,int f,int dist) {
	sz[x]=1;
	mx[Rt]=max(mx[Rt],dist);
	dis[x][cnt[x]]=dist; cnt[x]++;
	for(int i=hd[x],y;i;i=ne[i]) 
		if(!vis[y=to[i]] && y!=f) Getdist(y,x,dist+1), sz[x]+=sz[y];
}

inline void Solve(int x) {
	vis[x]=1;
	for(int i=hd[x],y;i;i=ne[i]) if(!vis[y=to[i]]) {
		Mx=inf; all=sz[y]; Getroot(y,0); 
		Getdist(Rt,0,0); New(Rt,mx[Rt],mx[x]);
		Fa[Rt]=x; Solve(Rt);
	}
}

inline void Build(int p) {
	int x=p,las=0,tmp=0;
	while(x) {
		T1.Modify(x,dis[p][tmp]+1,a[p]);
		if(Fa[x]) T2.Modify(x,dis[p][tmp+1]+1,a[p]);
		tmp++; x=Fa[x];
	}
}

inline void Change(int p,int v) {
	int x=p,tmp=0;
	while(x) {
		T1.Modify(x,dis[p][tmp]+1,v-a[p]);
		if(Fa[x]) T2.Modify(x,dis[p][tmp+1]+1,v-a[p]);
		tmp++; x=Fa[x];
	}
	a[p]=v;
}

inline int Ask(int p,int k) {
	int res=0,x=p,tmp=0,las=0;
	while(x) {
		if(k>=dis[p][tmp]) res+=T1.Query(x,k-dis[p][tmp]+1);
		if(las && k>=dis[p][tmp]) res-=T2.Query(las,k-dis[p][tmp]+1);
		tmp++; las=x; x=Fa[x];
	}
	return res;
}

待更。

标签:tmp,sz,int,分治,T2,笔记,学习,now
From: https://www.cnblogs.com/oscaryangzj/p/16845797.html

相关文章

  • 线性基学习笔记
    线性基概念:线性基就是一组基(啊说通俗一点点就是一组数字),这一组基相互进行异或操作能够表示出给定原集合的所有异或和,我们一般选择最简单的一组。可用于每一个亦或和的排......
  • SpringMVC笔记
    目录一、SpringMVC简介1、什么是MVC2、什么是SpringMVC3、SpringMVC的特点二、HelloWorld1、开发环境2、创建maven工程a>添加web模块b>打包方式:warc>引入依赖3、配置web.xm......
  • 程序员修炼之道第四章读书笔记与感悟
               程序员修炼之道第四章读书笔记与感悟程和其他工程技术一样,是一项充满细节的工作,追踪这些细节需要专注。且要能持续地作出大大小小的改进......
  • 《程序员修炼之道:从小工到专家》阅读笔记4
    如果你自己找不到答案,就去找出能找到答案的人。不要把问题搁在那里。与他人交谈可以帮助你建立人际网络,而因为在这个过程中找到了其他不相关问题的解决方案,你也许还会让自......
  • 2022.10.31python学习第二天
    python集合(数组)1.列表:是一种有序和可更改的集合,允许重复的成员   列表用 []来编号  可通过索引号来访问列表项  ......
  • 程序员修炼之道:从小工到专家读书笔记(复制)
    其实对于我们步入大学以后才接触到编程的人来说,我们没有基础,更没有稳固的知识储备,这更是考验我们能力的时期,我们在大学的学习过后可能会成为哪种高不成低不就的中手,需要高......
  • 2022_CMU15445_lab0笔记(Trie)
    预备工作环境我在windowswsl2中使用docker,docker是编译环境,wsl是编码环境,用共享目录的形式将docker目录和wsl2关联,用vscode编码剩下的环境配置直接参考https://gi......
  • 机器学习 之 朴素贝叶斯(Naive Bayesian Model)文本算法的精确率
    目录​​0、推荐​​​​1、背景​​​​2、效果图​​​​3、本次实验整体流程​​​​4、源代码​​​​6、知识点普及​​​​6.1朴素贝叶斯优点​​​​6.2朴素贝叶斯......
  • 10月份读书笔记
    读书笔记3纯文本的威力:优点:可读性远大于二进制,且不依赖特定的应用解码,因此不会过时。为了增加纯文本可读性,应该使用能够理解的词语。另外纯文本可由任何应用读取,因此适合......
  • 机器学习 之 K近邻(K-NearestNeighbor)文本算法的精确率
    目录​​0、推荐​​​​1、背景​​​​2、效果图​​​​3、本次实验整体流程​​​​4、这里不用词向量,而是用TF-IDF预处理后的向量​​​​5、源代码​​​​6、知识点......