BZOJ_3626_[LNOI2014]LCA_离线+树剖

题意:

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求$\sum\limits_{l\le i\le r}dep(LCA(i,z))$。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

分析:

求$\sum\limits_{l\le i\le r}dep(LCA(i,z))$相当于把[l,r]区间内所有点依次插入。

每次把点到1路径上所有点+1,可以发现z到1路径上的点权和即为所求。

并且该操作具有区间可减性。那么我们把所有询问拆成[0~l-1],[0~r]两部分。

排个序离线计算。

代码:

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 100050
#define LL long long
#define ls p<<1
#define rs p<<1|1
int head[N],to[N<<1],nxt[N<<1],cnt,n,m,r,mod=201314;
int t[N<<2],lz[N<<2],tot;
int siz[N],top[N],son[N],fa[N],dep[N],idx[N];
LL now,ans[N];
struct A{
int pos,z,flg,id;
}a[N];
bool cmp(const A &x,const A &y){
return x.pos<y.pos;
}
inline void add(int u,int v){
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void dfs1(int x,int y){
fa[x]=y;dep[x]=dep[y]+1;siz[x]=1;
for(int i=head[x];i;i=nxt[i]){
if(to[i]!=y){
dfs1(to[i],x);
siz[x]+=siz[to[i]];
if(siz[to[i]]>siz[son[x]])son[x]=to[i];
}
}
}
void dfs2(int x,int t){
top[x]=t;idx[x]=++tot;
if(son[x])dfs2(son[x],t);
for(int i=head[x];i;i=nxt[i]){
if(to[i]!=fa[x]&&to[i]!=son[x])dfs2(to[i],to[i]);
}
}
void pud(int l,int r,int p){
if(!lz[p])return ;
int mid=l+r>>1;
lz[ls]=(lz[ls]+lz[p])%mod;
lz[rs]=(lz[rs]+lz[p])%mod;
t[ls]=(t[ls]+lz[p]*(mid-l+1))%mod;
t[rs]=(t[rs]+lz[p]*(r-mid))%mod;
lz[p]=0;
}
void up(int l,int r,int x,int y,int c,int p){
if(x<=l&&r<=y){
lz[p]=(lz[p]+c)%mod;
t[p]=(t[p]+c*(r-l+1))%mod;return ;
}
pud(l,r,p);
int mid=l+r>>1;
if(x<=mid)up(l,mid,x,y,c,ls);
if(y>mid)up(mid+1,r,x,y,c,rs);
t[p]=(t[ls]+t[rs])%mod;
}
int query(int l,int r,int x,int y,int p){
if(x<=l&&r<=y){
return t[p];
}
pud(l,r,p);
int mid=l+r>>1;
int re=0;
if(x<=mid)re=(re+query(l,mid,x,y,ls))%mod;
if(y>mid)re=(re+query(mid+1,r,x,y,rs))%mod;
return re;
}
void insert(int x){
int y=1;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]])swap(x,y);
up(1,n,idx[top[y]],idx[y],1,1);
y=fa[top[y]];
}if(dep[x]<dep[y])swap(x,y);
up(1,n,idx[y],idx[x],1,1);
}
LL ask(int x){
LL re=0;
int y=1;
while(top[x]!=top[y]){
if(dep[top[x]]>dep[top[y]])swap(x,y);
re+=query(1,n,idx[top[y]],idx[y],1);
re%=mod;
y=fa[top[y]];
}if(dep[x]<dep[y])swap(x,y);
re+=query(1,n,idx[y],idx[x],1);
re%=mod;
return re;
}
int main(){
scanf("%d%d",&n,&m);
int x;
for(int i=2;i<=n;i++){
scanf("%d",&x);x++;
add(x,i);add(i,x);
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a[i].pos,&a[i+m].pos,&a[i].z);
a[i+m].pos++;a[i].z++;
a[i+m].z=a[i].z;a[i].id=a[i+m].id=i;a[i+m].flg=1;
}
sort(a+1,a+m+m+1,cmp);
int dir=0;
for(int i=1;i<=m+m;i++){
if(dir==a[i].pos){
ans[a[i].id+a[i].flg*m]=ask(a[i].z);continue;
}else{
for(int j=dir+1;j<=a[i].pos;j++){
insert(j);
}
ans[a[i].id+a[i].flg*m]=ask(a[i].z);dir=a[i].pos;
}
}
for(int i=1;i<=m;i++){
printf("%lld\n",(ans[i+m]-ans[i]+mod)%mod);
} }
/* 5 2
0
0
1
1
1 4 3
1 4 2
*/

BZOJ_3626_[LNOI2014]LCA_离线+树剖的更多相关文章

  1. BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...

  2. [LNOI2014]LCA(树剖+线段树)

    \(\%\%\% Fading\) 此题是他第一道黑题(我的第一道黑题是蒲公英) 一直不敢开,后来发现是差分一下,将询问离线,树剖+线段树维护即可 \(Code\ Below:\) #include ...

  3. bzoj 3626: [LNOI2014]LCA 离线+树链剖分

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

  4. bzoj3626: [LNOI2014]LCA奇技淫巧+树剖+线段树

    题目求[a,b]到c的lca深度之和   显然是一个满足区间减法的操作 于是简化为 [1,b]到c的lca深度之和 (然并卵╮(╯▽╰)╭)然后就用奇技淫巧发现 a和b的lca深度=先把根节点到a的路 ...

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

    [BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...

  6. [BZOJ3626] [LNOI2014] LCA 离线 树链剖分

    题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...

  7. BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)

    BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...

  8. 【BZOJ 3626】 [LNOI2014]LCA【在线+主席树+树剖】

    题目链接: TP 题解:   可能是我比较纱布,看不懂题解,只好自己想了…… 先附一个离线版本题解[Ivan] 我们考虑对于询问区间是可以差分的,然而这并没有什么卵用,然后考虑怎么统计答案. 首先LC ...

  9. HDU 6162 Ch’s gift (树剖 + 离线线段树)

    Ch’s gift Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total S ...

随机推荐

  1. android + php 后台开发

    android+php 安卓与服务器的数据交互 在我们进行android开发的时候,避免不了的要进行登录注册,个人信息获取,数据交互等等这一系列的操作.这样就需要进行android端与服务器端进行数据 ...

  2. oracle 修改 字段名称

    暂时应该没有对应的方法,所以我用自己想好的方法去修改 /*修改原字段名name为name_tmp,是将想改名称的字段改为没用/临时的字段*/ Alter  table 表名 rename column ...

  3. INCA二次开发-MIP

    1.INCA介绍 INCA是常用的汽车ECU测试和标定的,广泛应用于动力总成等领域.INCA提供了丰富的接口,供用户自动化.定制化.本公众号通过几篇文章,介绍下一些二次开发的方法,本篇介绍MIP. 2 ...

  4. Python学习摘要201802

    [基础]变量设计机制 [个人理解]python的变量与C++语言中的指针类似,是指向内存数据的一个引用.变量分为不可变变量string/int/float/tuple和可变变量list/dict. 对 ...

  5. HTML5这个概念的解释

    关于HTML5这个概念我一直很多困惑,稍微总结一下. 从HTML说起,HTML作为一个标记语言,通过这种标记定义了一个网页的dom tree,也定义了网页的结构,然后CSS定义了在这个结构基础上的样式 ...

  6. Python和Java的硬盘夜话

    这是一个程序员的电脑硬盘,在一个叫做"学习"的目录下曾经生活着两个小程序,一个叫做Hello.java,即Java小子:另外一个叫做hello.c ,也就是C老头儿. C老头儿的命 ...

  7. VS2010+OpenMP的简单使用

    OpenMP是把程序中的循环操作分给电脑的各个CPU处理器并行进行.比如说我要循环运行100次,我的电脑有两个处理器,那OpenMP就会平均分给两个处理器并行运行,每个处理器运行50次.使用方法 1. ...

  8. JDK1.8的新特性

    JAVA8新特性 接口改善 现在接口里已经完全可以定义静态方法了. 举一个比较普遍的例子就是在java类库中, 对于一些接口如Foo, 都会有一个有静态方法的工具类Foos 来生成或者配合Foo对象实 ...

  9. ionic常见问题及解决方案

    1.Android SDK install设置代理服务器mirrors.neusoft.edu.cn80force http 2.ionic build android 2.1 gradle下载不了解 ...

  10. 【转】sentry 实时事件日志聚合平台

    1.install postgreSQL(v9.6)2.pip install sentry(v8.13.0)3.sentry init #初始化配置文件 4.配置好postgreSQL 需要连接re ...