BZOJ 3626 LCA(离线+树链剖分+差分)

显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r
之间的点,向上搜索到第一个有标记的点求出它的深度统计答案。观察到,深度其实就是上面有几个已标记了的点(包括自身)。所以,我们不妨把 z
到根的路径上的点全部 +1,对于 l 到 r
之间的点询问他们到根路径上的点权和。仔细观察上面的暴力不难发现,实际上这个操作具有叠加性,且可逆。也就是说我们可以对于 l 到 r 之间的点
i,将 i 到根的路径上的点全部 +1, 转而询问 z 到根的路径上的点(包括自身)的权值和就是这个询问的答案。把询问差分下,也就是用 [1,
r] − [1, l − 1] 来计算答案,那么现在我们就有一个明显的解法。从 0 到 n − 1 依次插入点 i,即将 i
到根的路径上的点全部+1。离线询问答案即可。我们现在需要一个数据结构来维护路径加和路径求和,显然树链剖分或LCT
均可以完成这个任务。树链剖分的复杂度为 O((n + q)· log n · log n),LCT的复杂度为 O((n + q)· log
n),均可以完成任务。至此,题目已经被我们完美解决。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
const long long N=;
const long long mod=;
long long cnt,head[N];
long long size[N],fa[N],dep[N],son[N];
long long top[N],id[N],tot;
long long n,m,lm[N],rm[N];
struct que{
long long l,r,z;
}q[N];
struct tree{
long long l,r,sum,lazy;
}tr[N*];
vector<long long> l[N],r[N];
struct edge{
long long to,nxt;
}e[N*];
void add(long long u,long long v){
cnt++;
e[cnt].nxt=head[u];
e[cnt].to=v;
head[u]=cnt;
}
void dfs1(long long u,long long f,long long deep){
size[u]=;
fa[u]=f;
dep[u]=deep;
long long maxson=-;
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==f)continue;
dfs1(v,u,deep+);
size[u]+=size[v];
if(size[v]>maxson){
maxson=size[v];
son[u]=v;
}
}
}
void dfs2(long long u,long long tp){
top[u]=tp;
id[u]=++tot;
if(!son[u])return;
dfs2(son[u],tp);
for(long long i=head[u];i;i=e[i].nxt){
long long v=e[i].to;
if(v==fa[u]||v==son[u])continue;
dfs2(v,v);
}
}
void build(long long l,long long r,long long now){
tr[now].l=l;tr[now].r=r;
if(l==r)return;
long long mid=(l+r)>>;
build(l,mid,now*);
build(mid+,r,now*+);
}
void update(long long now){
tr[now].sum=tr[now*].sum+tr[now*+].sum;
tr[now].sum%=mod;
}
void pushdown(long long now){
if(tr[now].lazy==)return;
tr[now*].sum+=((tr[now*].r-tr[now*].l+)*tr[now].lazy)%mod;
tr[now*].sum%=mod;
tr[now*+].sum+=((tr[now*+].r-tr[now*+].l+)*tr[now].lazy)%mod;
tr[now*+].sum%=mod;
tr[now*].lazy+=tr[now].lazy;
tr[now*].lazy%=mod;
tr[now*+].lazy+=tr[now].lazy;
tr[now*+].lazy%=mod;
tr[now].lazy=;
}
void change(long long l,long long r,long long now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
tr[now].sum+=(tr[now].r-tr[now].l+)%mod;
tr[now].sum%=mod;
tr[now].lazy+=;
return;
}
long long mid=(tr[now].l+tr[now].r)>>;
if(l>mid)change(l,r,now*+);
else if(r<=mid)change(l,r,now*);
else{
change(l,mid,now*);
change(mid+,r,now*+);
}
update(now);
}
long long getsum(long long l,long long r,long long now){
pushdown(now);
if(tr[now].l==l&&tr[now].r==r){
return tr[now].sum;
}
long long mid=(tr[now].l+tr[now].r)>>;
if(l>mid)return getsum(l,r,now*+);
else if(r<=mid)return getsum(l,r,now*);
else {
return (getsum(l,mid,now*)+getsum(mid+,r,now*+))%mod;
}
}
void changel(long long x,long long y){
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
change(id[top[x]],id[x],);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
change(id[x],id[y],);
}
long long getsuml(long long x,long long y){
long long ans=;
while(top[x]!=top[y]){
if(dep[top[x]]<dep[top[y]])swap(x,y);
ans+=getsum(id[top[x]],id[x],);
ans%=mod;
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
ans+=getsum(id[x],id[y],);
ans%=mod;
return ans;
}
int main(){
scanf("%lld%lld",&n,&m);
for(long long i=;i<=n;i++){
long long u;
scanf("%lld",&u);
add(u+,i);add(i,u+);
}
dfs1(,,);
dfs2(,);
build(,n,);
for(long long i=;i<=m;i++){
scanf("%lld%lld%lld",&q[i].l,&q[i].r,&q[i].z);
q[i].l++;q[i].r++;q[i].z++;
l[q[i].l-].push_back(i);
r[q[i].r].push_back(i);
}
for(long long i=;i<=n;i++){
changel(i,);
for(long long j=;j<l[i].size();j++){
lm[l[i][j]]=getsuml(q[l[i][j]].z,);
}
for(long long j=;j<r[i].size();j++){
rm[r[i][j]]=getsuml(q[r[i][j]].z,);
}
}
for(long long i=;i<=m;i++){
printf("%lld\n",(rm[i]-lm[i]+mod)%mod);
}
return ;
}
BZOJ 3626 LCA(离线+树链剖分+差分)的更多相关文章
- BZOJ 3626 LCA(离线+树链剖分)
首先注意到这样一个事实. 树上两个点(u,v)的LCA的深度,可以转化为先将u到根路径点权都加1,然后求v到根路径上的总点权值. 并且该题支持离线.那么我们可以把一个区间询问拆成两个前缀和形式的询问. ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- [BZOJ3626] [LNOI2014] LCA 离线 树链剖分
题面 考虑到询问的\(l..r,z\)具有可减性,考虑把询问差分掉,拆成\(r,z\)和\(l-1,z\). 显然这些LCA一定在\(z\)到根的路径上.下面的问题就是怎么统计. 考虑不是那么暴力的暴 ...
- 【BZOJ3626】[LNOI2014]LCA 离线+树链剖分+线段树
[BZOJ3626][LNOI2014]LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度 ...
- 【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
[BZOJ3626]LCA(树链剖分,Link-Cut Tree) 题面 Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. ...
- BZOJ 3626 离线+树链剖分+线段树
思路: 抄一波yousiki的- 显然,暴力求解的复杂度是无法承受的. 考虑这样的一种暴力,我们把 z 到根上的点全部打标记,对于 l 到 r 之间的点,向上搜索到第一个有标记的点求出它的深度统计答案 ...
- 【树链剖分 差分】bzoj3626: [LNOI2014]LCA
把LCA深度转化的那一步还是挺妙的.之后就是差分加大力数据结构了. Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep ...
- JZYZOJ1454 NOIP2015 D2T3_运输计划 二分 差分数组 lca tarjan 树链剖分
http://172.20.6.3/Problem_Show.asp?id=1454 从这道题我充分认识到我的脑子里好多水orz. 如果知道了这个要用二分和差分写,就没什么思考上的难点了(屁咧你写了一 ...
- BZOJ 2243: [SDOI2011]染色 树链剖分 倍增lca 线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
随机推荐
- (转载)Android之有效防止按钮多次重复点击的方法(必看篇)
为了防止测试妹子或者用户频繁点击某个按钮,导致程序在短时间内进行多次数据提交or数据处理,那到时候就比较坑了~ 那么如何有效避免这种情况的发生呢? 我的想法是,判断用户点击按钮间隔时间,如果间隔时间太 ...
- 「JavaSE 重新出发」02. 数据类型与运算符
「TOC」 Java 程序基本要求 Java 数据类型 基本数据类型 复合数据类型 运算符 逻辑运算符 位运算符 运算符优先级 Java 程序基本要求 public class : 一个 Java 文 ...
- 《Unix环境高级编程》读书笔记 第4章-文件和目录
1. stat结构的基本形式: on error 24. 设备特殊文件 每个文件系统所在的存储设备都由其主.次设备号表示. 设备号所用的数据类型是基本系统数据类型dev_t. 主设备号标识设备驱动程序 ...
- (一)React再学习
新公司的技术栈是React,虽然之前对react大概过了一遍,但是自己没有实际落地过项目 再学习一遍react: 一.react全家桶 ·create-react-app ·组件化思维 ·JSX ·开 ...
- 影像服务——加载CESIUM自带的影像服务
1.加载arcgis数据——ArcGisMapServerImageryProvider var viewer = new Cesium.Viewer("cesiumDiv",{ ...
- POJ-3169 Layout 最短路 差分约束
题目链接:https://cn.vjudge.net/problem/POJ-3169 题意 Farmer John手下的一些牛有自己喜欢的牛,和讨厌的牛 喜欢的牛之间希望距离在给定距离D之内 讨厌的 ...
- BZOJ 2246 [SDOI2011]迷宫探险 (记忆化搜索)
题目大意:太长了,略 bzoj luogu 并没有想到三进制状压 题解: 3进制状压陷阱的状态,0表示这种陷阱的状态未知,1已知危险,2已知不危险 然后预处理出在当前状态下,每种陷阱有害的概率,设为$ ...
- Vue内置指令
v-text 类型: string用法: 更新元素的 textContent.如果要更新部分的 textContent ,需要使用 {{ Mustache }} 插值. v-html 类型: stri ...
- 紫书 例题11-9 UVa 1658 (拆点+最小费用流)
这道题要求每个节点只能经过一次,也就是结点容量为1, 要拆点, 拆成两个点, 中间连一条弧容量为1, 费用为0. 因为拆成两个点, 所以要经过原图中的这个节点就要经过拆成的这两个点, 又因为这两个点的 ...
- Linux入门基础(一)
UNIX/Linux 本身是没有图形界面的,我们通常在 UNIX/Linux 发行版上看到的图形界面实际都只是运行在 Linux 系统之上的一套软件XFree86,现在则是 xorg(X.Org),而 ...