传送门

长链剖分模板题。

题意简述:允许O(nlogn)O(nlog_n)O(nlogn​)预处理,让你支持O(1)O(1)O(1)查找任意一个点的kkk级祖先。


思路:因为要O(1)O(1)O(1)求,因此需要用到长链剖分的一些性质。

所谓长链剖分是类比重链剖分的一种划分树的方式,我们考虑将整棵树用若干条极长链拼接起来就是长链剖分。

那么它有如下几个几个性质:

  1. 所有长链的长度之和为O(n)O(n)O(n)
  2. 一个节点的kkk级祖先所在的长链的长度至少为kkk 可以根据长链剖分的定义想

    然后这题就可以做出来了。

具体实现:

对于长链的每一个上顶点ppp,我们设其引导的长链长度为lenlenlen,我们预处理出ppp的000 ~ lenlenlen级祖先和000~lenlenlen级的长儿子(即它引导的这条链),然后用O(nlogn)O(nlogn)O(nlogn)的时空预处理出一个祖先的倍增数组以及预处理一个数组highbithighbithighbit存每个数对应的二进制位最高位是第几位。

考虑一个查询(p,r)(p,r)(p,r)即查询ppp点的rrr级祖先。

我们先通过倍增数组将ppp跳到其2highbitr2^{highbit_{r}}2highbitr​级祖先yyy,然后剩下的r−highbitrr-highbit_rr−highbitr​是小于highbitrhighbit_rhighbitr​的,有性质2可以知道这个祖先一定存在yyy在的链顶上,然后就可以查出来了。

代码:

#include<bits/stdc++.h>
#define ri register int
using namespace std;
inline int read(){
	int ans=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
	return ans;
}
const int N=3e5+5;
int top[N],st[N][21],Log[N],n,m,dep[N],hson[N],mdep[N],highbit[N];
vector<int>e[N],son[N],anc[N];
inline void init(){
	Log[1]=0,highbit[1]=0;
	for(ri i=2;i<=n;++i)Log[i]=Log[i>>1]+1,highbit[i]=highbit[i-1]+(i>>(highbit[i-1]+1)&1);
	for(ri i=1;i<=n;++i){
		if(top[i]==i){
			int up=mdep[i]-dep[i];
			for(ri v=i,j=0;j<=up;++j)son[i].push_back(v),v=hson[v];
			for(ri v=i,j=0;j<=up;++j)anc[i].push_back(v),v=st[v][0];
		}
	}
	for(ri j=1;j<=20;++j)for(ri i=1;i<=n;++i)st[i][j]=st[st[i][j-1]][j-1];
}
void dfs1(int p){
	for(ri v,i=0;i<e[p].size();++i){
		if((v=e[p][i])==st[p][0])continue;
		st[v][0]=p,mdep[v]=dep[v]=dep[p]+1,dfs1(v),mdep[p]=max(mdep[v],mdep[p]);
		if(mdep[v]>mdep[hson[p]])hson[p]=v;
	}
}
void dfs2(int p,int tp){
	top[p]=tp;
	if(!hson[p])return;
	dfs2(hson[p],tp);
	for(ri i=0,v;i<e[p].size();++i){
		v=e[p][i];
		if(v==st[p][0]||v==hson[p])continue;
		dfs2(v,v);
	}
}
inline int query(int x,int k){
	if(k>dep[x])return 0;
	if(!k)return x;
	int y=st[x][highbit[k]];
	k-=1<<highbit[k];
	if(!k)return y;
	if(dep[y]-dep[top[y]]<=k)return anc[top[y]][k-dep[y]+dep[top[y]]];
	return son[top[y]][dep[y]-dep[top[y]]-k];
}
int main(){
	n=read();
	for(ri i=1,u,v;i<n;++i)u=read(),v=read(),e[u].push_back(v),e[v].push_back(u);
	dfs1(1),dfs2(1,1),init();
	for(ri tt=read(),lastans=0,x,k;tt;--tt)x=read()^lastans,k=read()^lastans,cout<<(lastans=query(x,k))<<'\n';
	return 0;
}

2019.01.06 vijos lxhgww的奇思妙想(长链剖分)的更多相关文章

  1. [vijos]lxhgww的奇思妙想(长链剖分)

    题意 题目链接 Sol 长链剖分 又是一个用各种花式技巧优化的暴力 它的主要思想是:对于每个节点,把深度最深的子节点当做重儿子,它们之间的边当做重边 这样就会有一些非常好的轻质 所有链长总和是\(O( ...

  2. lxhgww的奇思妙想 长链剖分板子

    https://vijos.org/d/Bashu_OIers/p/5a79a3e1d3d8a103be7e2b81 求k级祖先,预处理nlogn,查询o1 //#pragma GCC optimiz ...

  3. 「vijos-bashu」lxhgww的奇思妙想(长链剖分)

    倍增离线,预处理出爹和孙子们.查询\(O(1)\) #include <cstdio> #include <cstring> #include <numeric> ...

  4. 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)

    LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...

  5. 219.01.19 bzoj3252: 攻略(长链剖分+贪心)

    传送门 长链剖分好题. 题意:给一棵带点权的树,可以从根节点到任一叶节点走kkk次,走过的点只能计算一次,问kkk次走过的点点权值和最大值. 思路: 考虑将整棵树带权长链剖分,这样链与链之间是不会重复 ...

  6. 2019.01.20 bzoj2238: Mst(kruskal+树链剖分)

    传送门 树链剖分菜题. 题意简述:给一个无向图,边有边权,每次询问删一条边(对后面的询问无影响)之后的最小生成树. 思路: 先跑一次kruskalkruskalkruskal并把跑出来的最小生成树给链 ...

  7. 2019.01.20 bzoj3999: [TJOI2015]旅游(树链剖分)

    传送门 树链剖分菜题. 题意不清差评. 题意简述(保证清晰):给一棵带权的树,每次从aaa走到bbb,在走过的路径上任意找两个点,求后访问的点与先访问的点点权差的最大值. 思路: 考虑暴力:维护路径的 ...

  8. 2019.01.13 bzoj4538: [Hnoi2016]网络(树链剖分)

    传送门 树链剖分一眼题. 题意简述: 给定一棵树,有三种操作: 加入一条路径 删除一条已加入的路径 询问不过一个点x的路径的最大值. 思路: 直接树链剖分维护答案. 因为询问的事不过点xxx的最大值, ...

  9. 【Vijos】lxhgww的奇思妙想(长链剖分)

    题面 给定一棵树,每次询问一个点的\(k\)次祖先,强制在线. Vijos 题解 长链剖分. 链接暂时咕咕咕了. 现在可以戳链接看题解了 #include<iostream> #inclu ...

随机推荐

  1. e-olymp Problem8352 Taxi

    作为我在这个OJ玩了一下午的终结吧. 水题一道,阅读理解OJ. 传送门:点我 Taxi At the peak hour, three taxi buses drove up at the same ...

  2. java 对一个字符串去重,即去掉字符串内重复元素

    String str ="abc|efa|abc|efa|abc"; String str1 = str.replaceAll("(?s)(.)(?=.*\\1)&quo ...

  3. task 定时设置

    每天凌晨2点  0 0 2 * * ?和每天隔一小时 0 * */1 * * ? 例1:每隔5秒执行一次:*/5 * * * * ? 例2:每隔5分执行一次:0 */5 * * * ? 在26分.29 ...

  4. 单击Gridview中LinkButton,获取当前行索引及某单元格值,进行相关处理

    1.在Gridview中添加模板列,在其中加入Linkbuttion,增加CommandName属性 (设置命令名),并赋值 <asp:TemplateField HeaderText=&quo ...

  5. day 03

    1.数字类型 int 数字主要是用于计算用的,使用方法并不是很多,就记住一种就可以: bit_length()  当前十进制用二进制表示时,最少使用的位数 s = 5 print(s.bit_leng ...

  6. rviz1

    msckf_vio ####查看topic列表:wj@wj-Inspiron-5437:~$ rostopic list/benchmark_publisher/path/cam0/image_raw ...

  7. go语言中的strings常用函数和格式化输出

    package main; import ( "fmt" "strings" ) type person struct { name string; age i ...

  8. Liunx 重定向,管道符(转)

    原作网址:http://blog.csdn.net/qq_16811963/article/details/52997178 输出重定向 >代表以覆盖的方式将命令的正确输出输出到指定的文件或设备 ...

  9. 主机在无线网络的情况下,设置centos7.2虚拟机网络联通

    1.vmvare中,编辑-虚拟网络编辑器 2.虚拟机设置 3.进入linux登录后 输入nmtui 4激活连接 5大功告成,输入ping www.baidu.com  发现ping通了

  10. docker 运行nginx并进入容器内部、端口映射

    一.docker运行容器 1.从网易蜂巢镜像仓库下载nginx镜像 : 2.拉取镜像到本地,并查看本地的镜像: $ docker pull hub.c..com/library/node:latest ...