[BZOJ3626] [LNOI2014]LCA(树链剖分)

题面

给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和。N, Q≤50000

分析

对于一个点i,我们把i到根节点的路径全部标记+1,然后从z往上找,第一个碰到的标记不为0的节点就是lca(z,i)。而i的深度恰好就是z到根节点路径上的标记和。显然这样的标记是可以叠加的,对于区间[l,r],我们把编号在[l,r]内的节点到根的路径都标记+1,那么答案就在z到根路径上的标记和。

但是这样直接做还是\(O(n^2)\)的,考虑离线。注意到标记是可减的,那么询问query(l,r,z)就相当于query(1,r,z)-query(1,l-1,z)。

那么我们分两部分维护答案,记query(1,r,z)=ansr,query(1,l-1,z)=ansl,真正的答案就是ansr-ansl.我们对于每个点,保存左端点l-1在此的询问编号,右端点同理。我们从1~n遍历每个节点i,把i到根的路径标记+1。然后看看有没有左端点在i的询问,如果有,就更新ansl,右端点同理

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define maxn 50000
#define mod 201314
using namespace std;
int n,m;
struct edge{
int from;
int to;
int next;
}E[maxn*2+5];
int head[maxn+5];
int esz=0;
void add_edge(int u,int v){
esz++;
E[esz].from=u;
E[esz].to=v;
E[esz].next=head[u];
head[u]=esz;
} int dfn[maxn+5];
int fa[maxn+5];
int son[maxn+5];
int sz[maxn+5];
int deep[maxn+5];
int top[maxn+5];
void dfs1(int x,int f){
fa[x]=f;
sz[x]=1;
deep[x]=deep[f]+1;
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(y!=f){
dfs1(y,x);
sz[x]+=sz[y];
if(sz[son[x]]<sz[y]) son[x]=y;
}
}
}
int tim=0;
void dfs2(int x,int t){
top[x]=t;
dfn[x]=++tim;
if(son[x]) dfs2(son[x],t);
for(int i=head[x];i;i=E[i].next){
int y=E[i].to;
if(y!=fa[x]&&y!=son[x]){
dfs2(y,y);
}
}
} struct segment_tree{
struct node{
int l;
int r;
long long mark;
long long v;
int len(){
return r-l+1;
}
}tree[maxn*4+5];
void push_up(int pos){
tree[pos].v=tree[pos<<1].v+tree[pos<<1|1].v;
}
void push_down(int pos){
if(tree[pos].mark){
tree[pos<<1].mark+=tree[pos].mark;
tree[pos<<1|1].mark+=tree[pos].mark;
tree[pos<<1].v+=tree[pos].mark*tree[pos<<1].len();
tree[pos<<1|1].v+=tree[pos].mark*tree[pos<<1|1].len();
tree[pos].mark=0;
}
}
void build(int l,int r,int pos){
tree[pos].l=l;
tree[pos].r=r;
if(l==r) return;
int mid=(l+r)>>1;
build(l,mid,pos<<1);
build(mid+1,r,pos<<1|1);
push_up(pos);
}
void update(int L,int R,long long val,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
tree[pos].mark+=val;
tree[pos].v+=val*tree[pos].len();
return;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
if(L<=mid) update(L,R,val,pos<<1);
if(R>mid) update(L,R,val,pos<<1|1);
push_up(pos);
}
long long query(int L,int R,int pos){
if(L<=tree[pos].l&&R>=tree[pos].r){
return tree[pos].v;
}
push_down(pos);
int mid=(tree[pos].l+tree[pos].r)>>1;
long long ans=0;
if(L<=mid) ans+=query(L,R,pos<<1);
if(R>mid) ans+=query(L,R,pos<<1|1);
return ans;
}
}T; void update_route(int x,int y,int val){
int tx=top[x],ty=top[y];
while(tx!=ty){
if(deep[tx]<deep[ty]){
swap(x,y);
swap(tx,ty);
}
T.update(dfn[tx],dfn[x],val,1);
x=fa[tx];
tx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
T.update(dfn[x],dfn[y],val,1);
}
long long query_route(int x,int y){
int tx=top[x],ty=top[y];
long long ans=0;
while(tx!=ty){
if(deep[tx]<deep[ty]){
swap(x,y);
swap(tx,ty);
}
ans+=T.query(dfn[tx],dfn[x],1);
x=fa[tx];
tx=top[x];
}
if(deep[x]>deep[y]) swap(x,y);
ans+=T.query(dfn[x],dfn[y],1);
return ans;
} struct query{
int l;
int r;
int z;
int id;
long long ansl;
long long ansr;
}q[maxn+5];
vector<int>lb[maxn+5];
vector<int>rb[maxn+5];
int main(){
int p;
scanf("%d %d",&n,&m);
for(int i=2;i<=n;i++){
scanf("%d",&p);
p++;
add_edge(i,p);
add_edge(p,i);
}
dfs1(1,0);
dfs2(1,1);
T.build(1,n,1);
for(int i=1;i<=m;i++){
scanf("%d %d %d",&q[i].l,&q[i].r,&q[i].z);
q[i].l++;
q[i].r++;
q[i].z++;
q[i].id=i;
lb[q[i].l-1].push_back(i);
rb[q[i].r].push_back(i);
}
for(int i=1;i<=n;i++){
update_route(i,1,1);
for(int j=0;j<lb[i].size();j++){
int u=lb[i][j];
q[u].ansl=query_route(q[u].z,1);
}
for(int j=0;j<rb[i].size();j++){
int u=rb[i][j];
q[u].ansr=query_route(q[u].z,1);
}
}
for(int i=1;i<=m;i++){
printf("%lld\n",(q[i].ansr-q[i].ansl)%mod);
}
}

[BZOJ3626] [LNOI2014]LCA(树链剖分)的更多相关文章

  1. BZOJ3626[LNOI2014]LCA——树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  2. bzoj3626 [LNOI2014]LCA——树链剖分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...

  3. BZOJ3626 [LNOI2014]LCA 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...

  4. bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...

  5. 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树

    题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...

  6. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  7. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  8. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...

  9. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

随机推荐

  1. JavaScript 的执行机制

    一.关于javascript javascript是一门单线程语言,在最新的HTML5中提出了Web Worker,但javascript是单线程这一核心仍未改变. 为什么js是单线程的语言?因为最初 ...

  2. 通过busybox制作根文件系统

    通过busybox制作根文件系统可以自定义选项,在制作的根文件系统中添加需要的命令,指定生成的根文件系统到相应的目录下. 一. 根文件系统的获取方式--->官网: https://busybox ...

  3. Spring Data Elasticsearch 用户指南

    https://www.jianshu.com/p/27e1d583aafb 翻译自官方文档英文版,有删减. BioMed Central Development Team version 2.1.3 ...

  4. ARM Cortex-M底层技术(2)—启动代码详解

    杂谈 工作了一天,脑袋比较乱.一直想把底层的知识写成一个系列,希望可以坚持下去.为什么要写底层的东西呢?首先,工作用到了这部分内容,最近和内部Flash打交道比较多,自然而然会接触到一些底层的东西:第 ...

  5. express 获取post 请求参数

    在 Express 中没有内置获取表单 POST 请求体的 API , 我们需要添加第三方插件库 安装: npm install --save body-parser 配置: var bodyPars ...

  6. Nginx安装与配置-Centos7

    Nginx是一款高性能免费开源网页服务器,也可用于反向代理和负载均衡服务器.该软件由伊戈尔·赛索耶夫于2004年发布,2019年3月11日,Nginx被F5 Networks以6.7亿美元收购.201 ...

  7. #10042. 「一本通 2.1 练习 8」收集雪花 || 离散化 || 双指针法 || C++ || LOJ

    题目:#10042. 「一本通 2.1 练习 8」收集雪花 看到网上没有这道题的题解,所以写一下. 要标记数字是否存在,看到x<=1e9,所以考虑用离散化,然后开一个last数组,last[i] ...

  8. centos 搭建svn服务器

    1 安装svnserve yum install subversion -y 2 创建仓库 mkdir /svn/rep1 -p mkdir /svn/rep2 -p svnadmin create ...

  9. 基于 Ansible 的 ELK 部署说明

    ELK-Ansible使用手册 ELK-Ansible 是基于 Ansible 的 Playbooks 研发的 ELK集群部署工具.本文将介绍如何使用 ELK-Ansible 快速部署 ELK 集群. ...

  10. 三星GT S7562 PIN 解锁方法

    三星GT S7562  PIN 解锁方法 请认真阅读完下文再进行操作,操作基本安全,请保证你手机电池有电续航超过1小时 首先把内存开和电话卡取出(以防万一数据丢失) 关机状态下: 同时按音量上下键 加 ...