传送门

长链剖分模板题。

题意简述:允许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. windows上安装Anaconda和python

    下载并安装 anaconda 先到https://www.continuum.io/downloads 下载anaconda, 现在的版本有python2.7版本和python3.5版本,下载好对应版 ...

  2. 被遗忘的having

    清明节后公司网站搞活动主要功能很简单就是实现一个消费送的功能.比如, 当天消费金额满5000 返回10%,5000 及以下 返 7% 的功能.本身这个功能不是很难,但是  这个功能跟上次的一个 新用户 ...

  3. RxJava笔记

    网上搜索了一些关于 RxJava 的东西,对RxJava的定义自己理解如下: RxJava是要一种逻辑简洁的,通过一种扩展的观察者模式,来实现异步的一种链式编程.

  4. selenium去掉下载弹窗

    from selenium import webdriver import time import urllib2 class Download(): def __init__(self): self ...

  5. c# ?. 空值传播运算符

    当左侧为空时不执行右侧代码,避免出现为null的错误,同时也避免了判断是否为null,可以和??一起连用,省了好多事.举例如下: 以前:var res=obj==null?5:obj.a; 现在:va ...

  6. Linux驱动之LED驱动编写

    从上到下,一个软件系统可以分为:应用程序.操作系统(内核).驱动程序.结构图如下:我们需要做的就是写出open.read.write等驱动层的函数.一个LED驱动的步骤如下: 1.查看原理图,确定需要 ...

  7. 2.git使用之git fetch和git push的区别

    . git fetch:相当于是从远程获取最新版本到本地,不会自动merge git fetch origin master git log -p master..origin/master git ...

  8. 时间处理:计算下一天日期,如输入"2004/12/31"(注释2014年12月31日),则输出"2005/1/1".

    /* ============================================================================ Name : Exercise.c Au ...

  9. ajax异步请求该嵌套还是并列?

    因为要查询两个数据库表才能确定我所需要的数据范围,所以前台js得发两次ajax请求.问题就是,这两个请求是嵌套着写:{发,接{发,接}}:还是并列着写:{发,接},{发,接} 好? 答案:如果2次aj ...

  10. XSS绕过速查表

    0x00 目录 0x01 常规插入及其绕过 1 Script 标签 绕过进行一次移除操作: <scr<script>ipt>alert("XSS")< ...