[BZOJ3626] [LNOI2014]LCA(树链剖分)
[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(树链剖分)的更多相关文章
- BZOJ3626[LNOI2014]LCA——树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- bzoj3626 [LNOI2014]LCA——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...
- BZOJ3626 [LNOI2014]LCA 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
随机推荐
- centos 6.5 安装 jdk 8
首先,检查是否已安装jdk,如果有,要先删除 rpm -qa|grep java rpm -e --nodeps filename 然后,从oracle官方网站下载jdk安装包:jdk-8u121-l ...
- RMQ Message ACK
原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11808680.html 消息持久化机制 消息丢失了,需要将队列持久化,即将autoDelete设置成f ...
- 记录ViewPager配合Fragment使用中遇到的一个问题
java.lang.IllegalStateException: FragmentManager is already executing transactions 如图所示: 当调用 notifyD ...
- TreeMap定制排序和自然排序
TreeMap定制排序和自然排序自然排序是实现Comparable接口的方法.代码如下: @Override public int compareTo(Object o) { if (o instan ...
- eclipse 报错:One or more constraints have not been satisfied.
接受 我有同样的问题.在我的maven项目中添加速度依赖关系后,我在标记选项卡中得到相同的错误.然后我注意到maven项目创建的web.xml文件具有servlet2.3模式.当我将其更改为servl ...
- B/S选择文件夹上传
1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...
- 史上最全最实用HBuilder快捷键大全
史上最全最实用HBuilder快捷键大全 一.文件操作二.编辑操作三.插入操作四.转义操作五.选择操作六.跳转操作七.查找操作八.运行九.视图一.文件操作新建菜单: ctrl + N新建: ctrl ...
- HTML与CSS中的文本个人分享
文本 标题元素 注意: 在一个HTML页面中最好只使用一个<h1>标题 因为浏览器只会抓取一个多了没用 示例代码: <body> <!-- 标题元素 - <h1&g ...
- scrapy xpath xpath('---').xpath('string(.)') 提取子元素全部文本
product.xpath("div//div[@class='a-row a-spacing-mini'][1]/div[2]").xpath('string(.)')
- JS-关闭当前窗口
不提示直接关闭 默认有提示,若希望不提示直接关闭则需要使用(并非兼容全部浏览器) window.opener=null; window.open('','_self'); window.close() ...