洛谷 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 ...
随机推荐
- web.xml 中 classpath 写法说明
简单理解,classpath就是代表 /WEB-INF /classes/ 这个路径(如果不理解该路径,就把一个web工程发布为war包,然后用winrar查看其包内路径就理解啦) 常用的场景: ...
- win10 设置C盘访问权限
“以管理员身份运行” cmd.exe C:\Windows\system32>icacls "C:\Program Files\Epic Games" /setintegri ...
- cocos2dx热更新tmx的一个坑
游戏项目中使用了tmx地图,当对tmx文件进行热更新时,进入该地图总是宕机,纠结了几小时终于发现,cocos读取tmx文件时,会默认tmx关联的图集文件和tmx在同一目录,然而那个图集文件并没有在热更 ...
- nmon工具
下载地址 1.http://nmon.sourceforge.net/pmwiki.php?n=Site.Download tar xvzf *.tar.gz,需要配置权限 chmod -x,同时配 ...
- Objective-C代码学习大纲(1)
2011-05-11 14:06 佚名 otierney 字号:T | T 本文为台湾出版的<Objective-C学习大纲>的翻译文档,系统介绍了Objective-C代码,很多名词为台 ...
- Docker修改时区
简介 docker容器打日志时间滞后8小时 方法 启动时修改时区 Docker修改默认时区 已启动的容器修改时区 进入容器docker exec -i -t [CONTAINNER] /bin/bas ...
- JAVA基础之multipart,urlencoded以及JSON
一.(enctype) 表单的默认编码方式 ajpplication/x-www-form-urlencoded 上传文件的编码方式 multipart/form-data 互联网应用常用编码 ...
- jquery 最全知识点图示
有个别错字,请原谅:谢谢 1.选择器 2.DOM操作 3.DOM 4.事件 5.Ajax
- Zabbix数据库表结构
上一篇:Zabbix分布式监控 acknowledges 当出现报错的时候记录 查看着张表记录了一个事件 actions 动作 自动发现 问题告警 恢复告警 自动注册 alerts 报警信息 同web ...
- synchronized和volatile的使用方法以及区别
先看看下面的例子: public class ThreadTest { public static void main(String[] args) { final Counter counter = ...