洛谷 P4211 [LNOI2014]LCA (树链剖分+离线)
题目:https://www.luogu.org/problemnew/solution/P4211
相当难的一道题,其思想难以用言语表达透彻。
对于每个查询,区间[L,R]中的每个点与z的lca肯定出现在z到根节点的路径上,则路径上的点会对结果产生贡献。那么可以对每个lca向根节点边走边给路径上的每个点贡献+1,求和后的结果就是该查询的答案。当然朴素地做肯定是不行地,可以用线段树维护每个点到根节点上的点贡献之和。
那么每次统计的话,等于将nloglog的复杂度重复q次,也不行。然而每次查询的区间可能会重叠,状态可以转移,考虑离线处理。
对查询根据右端点排序,将一个查询拆成[1,L-1] 和 [1,R]两部分,每次的结果是累计[L,R]中的点到根节点路径上的贡献之和,可以差分处理,所以用[1,R] 的累计之和 - [1, L-1] 的累计之和。
#include<algorithm>
#include<stdio.h>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#define lson rt<<1
#define rson rt<<1|1
#define Lson l,m,lson
#define Rson m+1,r,rson
using namespace std;
typedef long long LL;
const LL maxn =1e5+;
struct Edge{
LL to,next;
}E[maxn<<];
LL n,head[maxn],tot;
LL idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn],rnk[maxn];
LL a[maxn];
void init()
{
idx=tot=;
memset(head,-,sizeof(head));
dep[]=,fa[]=,size[]=;
memset(son,,sizeof(son));
}
void AddEdge(LL u,LL v)
{
E[tot] = (Edge){v,head[u]};
head[u]=tot++;
}
void dfs1(LL u)
{
size[u]=;
for(LL i=head[u];~i;i=E[i].next){
LL v=E[i].to;
if(v!=fa[u]){
fa[v]=u;
dep[v]=dep[u]+;
dfs1(v);
size[u]+=size[v];
if(size[son[u]]<size[v]) son[u]=v;
}
}
} void dfs2(LL u,LL topu)
{
top[u]= topu;
id[u] = ++idx;
rnk[idx] = u; //建树用
if(!son[u]) return;
dfs2(son[u],top[u]);
for(LL i=head[u];~i;i=E[i].next){
LL v=E[i].to;
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
} struct STtree{
LL sum,lazy;
}tree[maxn<<]; void pushup(LL rt)
{
tree[rt].sum = tree[lson].sum + tree[rson].sum;
} void pushdown(LL l,LL r,LL rt)
{
if(tree[rt].lazy){
LL add =tree[rt].lazy;
tree[lson].lazy += add;
tree[rson].lazy += add;
LL m = (l+r)>>;
tree[lson].sum += (m-l+)*add;
tree[rson].sum += (r-m)*add;
tree[rt].lazy=;
}
} void update(LL L,LL R,LL v,LL l=,LL r=n,LL rt=)
{
if(L<=l && R>=r){
tree[rt].lazy += v;
tree[rt].sum += (r-l+)*v;
return ;
}
pushdown(l,r,rt);
LL m = (l+r)>>;
if(L<=m) update(L,R,v,Lson);
if(R>m) update(L,R,v,Rson);
pushup(rt);
} LL query(LL L,LL R,LL l=,LL r= n,LL rt=)
{
if(L<=l && R>=r) return tree[rt].sum;
pushdown(l,r,rt);
LL m = (l+r)>>,ans=;
if(L<=m) ans+=query(L,R,Lson);
if(R>m) ans+=query(L,R,Rson);
//pushup(rt);
return ans;
} void UPDATE(LL u,LL v,LL w=)
{
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
update(id[top[u]],id[u],w);
u = fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
update(id[u],id[v],w);
} LL SUM(LL u,LL v)
{
LL ans = ;
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
ans += query(id[top[u]],id[u]);
u = fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
ans += query(id[u],id[v]);
return ans;
} struct Qeury{
LL pos,num,z;
bool tag;
bool operator < (const Qeury & rhs) const {return pos<rhs.pos;}
}que[maxn];
LL res[maxn];
const LL MOD = ; int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
LL q,u,v,tmp;
scanf("%lld %lld",&n,&q);
init();
for(LL i=;i<=n;++i){
scanf("%lld",&u); u++;
AddEdge(u,i);
AddEdge(i,u);
}
dfs1();
dfs2(,);
LL l,r,z,cnt = ;
for(LL i=;i<=q;++i){
scanf("%lld %lld %lld",&l,&r,&z); l++,r++,z++;
que[cnt++] = (Qeury){l-,i,z,};
que[cnt++] = (Qeury){r,i,z,};
}
sort(que,que+cnt);
LL cur =;
for(LL i=;i<cnt;++i){
while(cur<=que[i].pos){
UPDATE(,cur++);
}
if(que[i].tag) res[que[i].num] += SUM(,que[i].z);
else res[que[i].num] -=SUM(,que[i].z);
res[que[i].num] += MOD;
res[que[i].num] %=MOD;
}
for(LL i=;i<=q;++i){
printf("%lld\n",res[i]);
}
return ;
}
洛谷 P4211 [LNOI2014]LCA (树链剖分+离线)的更多相关文章
- 洛谷$P4211\ [LNOI2014]\ LCA$ 树链剖分+线段树
正解:树剖+线段树 解题报告: 传送门$QwQ$ 看到$dep[lca]$啥的就想到之前托腮腮$CSP$模拟$D1T3$的那个套路,,, 然后试下这个想法,于是$dep[lca(x,y)]=\sum_ ...
- 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了... -------------------------------------------------------------- ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- [LNOI2014]LCA 树链剖分 离线 前缀和 思维题
题目描述:给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. 有q次询问,每 ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- BZOJ2243 洛谷2486 [SDOI2011]染色 树链剖分
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ2243 题目传送门 - 洛谷2486 题意概括 一棵树,共n个节点. 让你支持以下两种操作,共m次操 ...
- BZOJ3626[LNOI2014]LCA——树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
随机推荐
- 判断asp.net中session过期方法的比较
重写继承page的OnInit()虚方法,在需要的界面上,继承这个类. 1.新建继承page类的类JudgeSession,实现接口成员. 2.重写OnInit()方法,判断session情况. 3. ...
- JavaScript------创建节点
代码: <script type="text/javascript"> var i = 0; function add(){ var inputNode = docum ...
- JSP状态管理 及 Cookie实例
HTTP协议的无状态性 无状态是指,当浏览器发送请求给服务器的时候,服务器响应客户端的请求. 但是当同一个浏览器再次发送请求给了服务器的时候,服务器并不知道它就是刚才那个浏览器. 简单地说,就是服务器 ...
- Javascript实现图片的预加载的完整实现
图片预加载是web开发中一种应用相当广泛的技术,比如我们在做图片翻转显示等特效的时候,为了让图片在转换的时候不出现等待,我们最好是先让图片下载到本地,然后在继续执行后续的操作.今天我们将来实现一个完整 ...
- JZOJ.5289【NOIP2017模拟8.17】偷笑
Description berber走进机房,边敲门边喊:“我是哔哔”CRAZY转过头:“我警告你,哔哔刚刚来过!”“呵呵呵呵……”这时,哔哔站了起来,环顾四周:“你们笑什么?……”巧了,发出笑声的人 ...
- Android自定义控件之圆形进度条ImageView
From:http://blog.csdn.net/xiadik/article/details/41648181package com.wangran.beautiful_girl_show.vie ...
- timepicker php strtotime 8hours
https://jqueryui.com/datepicker/ w timepicker datepicker 日期 时间 选择器 <script src="static/jquer ...
- 剑指Offer——求1+2+3+...+n
题目描述: 求1+2+3+...+n,要求不能使用乘除法.for.while.if.else.switch.case等关键字及条件判断语句(A?B:C). 分析: 递归实现. 代码: class So ...
- C++之贪吃蛇
#include<iostream> #include<cstdio> #include<cstdlib> #include<ctime> #inclu ...
- GITLAB服务基础
1.GITLAB介绍 一个基于GIT的源码托管解决方案基于Ruby on rails开发集成了nginx postgreSQL redis sidekiq等组件 2. 资源 官网:https://ab ...