2019.01.06 vijos lxhgww的奇思妙想(长链剖分)
传送门
长链剖分模板题。
题意简述:允许O(nlogn)O(nlog_n)O(nlogn)预处理,让你支持O(1)O(1)O(1)查找任意一个点的kkk级祖先。
思路:因为要O(1)O(1)O(1)求,因此需要用到长链剖分的一些性质。
所谓长链剖分是类比重链剖分的一种划分树的方式,我们考虑将整棵树用若干条极长链拼接起来就是长链剖分。
那么它有如下几个几个性质:
- 所有长链的长度之和为O(n)O(n)O(n)
- 一个节点的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的奇思妙想(长链剖分)的更多相关文章
- [vijos]lxhgww的奇思妙想(长链剖分)
题意 题目链接 Sol 长链剖分 又是一个用各种花式技巧优化的暴力 它的主要思想是:对于每个节点,把深度最深的子节点当做重儿子,它们之间的边当做重边 这样就会有一些非常好的轻质 所有链长总和是\(O( ...
- lxhgww的奇思妙想 长链剖分板子
https://vijos.org/d/Bashu_OIers/p/5a79a3e1d3d8a103be7e2b81 求k级祖先,预处理nlogn,查询o1 //#pragma GCC optimiz ...
- 「vijos-bashu」lxhgww的奇思妙想(长链剖分)
倍增离线,预处理出爹和孙子们.查询\(O(1)\) #include <cstdio> #include <cstring> #include <numeric> ...
- 【LOJ】#3014. 「JOI 2019 Final」独特的城市(长链剖分)
LOJ#3014. 「JOI 2019 Final」独特的城市(长链剖分) 显然我们画一条直径,容易发现被统计的只可能是直径某个距离较远的端点到这个点的路径上的值 用一个栈统计可以被统计的点,然后我们 ...
- 219.01.19 bzoj3252: 攻略(长链剖分+贪心)
传送门 长链剖分好题. 题意:给一棵带点权的树,可以从根节点到任一叶节点走kkk次,走过的点只能计算一次,问kkk次走过的点点权值和最大值. 思路: 考虑将整棵树带权长链剖分,这样链与链之间是不会重复 ...
- 2019.01.20 bzoj2238: Mst(kruskal+树链剖分)
传送门 树链剖分菜题. 题意简述:给一个无向图,边有边权,每次询问删一条边(对后面的询问无影响)之后的最小生成树. 思路: 先跑一次kruskalkruskalkruskal并把跑出来的最小生成树给链 ...
- 2019.01.20 bzoj3999: [TJOI2015]旅游(树链剖分)
传送门 树链剖分菜题. 题意不清差评. 题意简述(保证清晰):给一棵带权的树,每次从aaa走到bbb,在走过的路径上任意找两个点,求后访问的点与先访问的点点权差的最大值. 思路: 考虑暴力:维护路径的 ...
- 2019.01.13 bzoj4538: [Hnoi2016]网络(树链剖分)
传送门 树链剖分一眼题. 题意简述: 给定一棵树,有三种操作: 加入一条路径 删除一条已加入的路径 询问不过一个点x的路径的最大值. 思路: 直接树链剖分维护答案. 因为询问的事不过点xxx的最大值, ...
- 【Vijos】lxhgww的奇思妙想(长链剖分)
题面 给定一棵树,每次询问一个点的\(k\)次祖先,强制在线. Vijos 题解 长链剖分. 链接暂时咕咕咕了. 现在可以戳链接看题解了 #include<iostream> #inclu ...
随机推荐
- leetcode题库解答源码(python3)
下面和大家分享本人在leetcode上已经ace的题目源码(python3): 本人会持续更新!- class Leetcode_Solution(object): def twoSum_1(self ...
- PAT1021(dfs 连通分量)
A graph which is connected and acyclic can be considered a tree. The height of the tree depends on t ...
- json 相关知识
一:json标准格式: 标准JSON的合法符号:{(左大括号) }(右大括号) "(双引号) :(冒号) ,(逗号) [(左中括号) ](右中括号) JSON字符串:特殊字符可在 ...
- JavaScript各种继承方式(六):寄生组合继承
一 原理 用寄生继承来改造组合继承. function Fruit(name){ this.name = name; } Fruit.prototype.eat = function(){ conso ...
- php使用fputcsv进行大数据的导出
为了实验大数据的导出,我们这里先自已创建一张大表,表结构如下: CREATE TABLE `tb_users` ( `id` int(11) unsigned NOT NULL AUTO_INCREM ...
- git 远程仓库与本地项目关联
在git 中创建一个项目或仓库如起名blog,生成README.md文件,在本地创建一个项目名为blog ,blog里面是代码,此时执行 git remote add origin <ssh协 ...
- Liunx 重定向,管道符(转)
原作网址:http://blog.csdn.net/qq_16811963/article/details/52997178 输出重定向 >代表以覆盖的方式将命令的正确输出输出到指定的文件或设备 ...
- PAT 1089 狼人杀-简单版(20 分)(代码+测试点分析)
1089 狼人杀-简单版(20 分) 以下文字摘自<灵机一动·好玩的数学>:"狼人杀"游戏分为狼人.好人两大阵营.在一局"狼人杀"游戏中,1 号玩家 ...
- 开源防火墙(pfSense)的安装部署与配置
pfSense是一个基于FreeBSD架构的软件防火墙,通常会被安装在多网卡的主板上作为路由器或者防火墙去使用.往往这些硬件都比较廉价,高性能的配置也就1千元左右.pfSense具有商业防火墙的大部分 ...
- VS2010下MFC的串口编程
串口通信简介 一般来说,计算机都有一个或多个串行端口,这些串口提供了外部设备与PC进行数据传输和通信的通道,在CPU和外设之间充当解释器的角色.当字符数据从CPU发送给外设时,这些字符数据将被转换成串 ...