BZOJ 3626: [LNOI2014]LCA(树剖+差分+线段树)
解题思路
比较有意思的一道题。首先要把求\(\sum\limits_{i=l}^r dep[lca(i,z)]\)这个公式变一下。就是考虑每一个点的贡献,做出贡献的点一定在\(z\)到根节点的路径上,对于\(x\)这个点,它的贡献就是区间\([l,r]\)与\(z\)的\(lca\)在它下方的个数。那么就可以将区间内的每一个点到根的路径权值都\(+1\),然后求一下\(z\)到根节点的权值即为答案,这样的话用线段树就行了。但每次询问要暴力清空线段树,时间复杂度是\(O(qnlog^2n)\)的,承受不住。现在考虑怎样优化一下\(q\),首先询问是可以拆成两端的,就是\([1,r]-[1,l-1]\)的形式,然后这样的话就不用暴力清空了。只需要离线预处理,把区间拆成两部分,按右端点排序(左端点都是\(1\)),然后每次修改时只需要修改当前询问到上一个询问这段区间就行了,修改时每个点最多只会被改一次。时间复杂度\(O(nlog^2n)\)
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int MAXN = 50005;
const int MOD = 201314;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return f?x:-x;
}
int n,Q,head[MAXN],cnt,to[MAXN<<1],nxt[MAXN<<1],ans[MAXN];
int dep[MAXN],siz[MAXN],son[MAXN],fa[MAXN],top[MAXN],id[MAXN],num;
int sum[MAXN<<2],tag[MAXN<<2];
struct Query{
int pos,type,id,z;
friend bool operator<(const Query A,const Query B){
return A.pos<B.pos;
}
}q[MAXN<<1];
inline void add(int bg,int ed){
to[++cnt]=ed,nxt[cnt]=head[bg],head[bg]=cnt;
}
void dfs1(int x,int f,int d){
fa[x]=f;dep[x]=d;siz[x]=1;
int maxson=-1,u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==f) continue;
dfs1(u,x,d+1);siz[x]+=siz[u];
if(siz[u]>maxson) {maxson=siz[u];son[x]=u;}
}
}
void dfs2(int x,int topf){
id[x]=++num;top[x]=topf;if(!son[x]) return;
dfs2(son[x],topf);int u;
for(int i=head[x];i;i=nxt[i]){
u=to[i];if(u==fa[x] || u==son[x]) continue;
dfs2(u,u);
}
}
inline void pushdown(int x,int ln,int rn){
sum[x<<1]+=tag[x]*ln%MOD;sum[x<<1]%=MOD;
sum[x<<1|1]+=tag[x]*rn%MOD;sum[x<<1|1]%=MOD;
tag[x<<1]+=tag[x];tag[x<<1|1]+=tag[x];tag[x]=0;
}
void update(int x,int l,int r,int L,int R){
if(L<=l && r<=R) {sum[x]+=r-l+1;sum[x]%=MOD;tag[x]++;return;}
int mid=(l+r)>>1;if(tag[x]) pushdown(x,mid-l+1,r-mid);
if(L<=mid) update(x<<1,l,mid,L,R);
if(mid<R) update(x<<1|1,mid+1,r,L,R);
sum[x]=sum[x<<1]+sum[x<<1|1];sum[x]%=MOD;
}
int query(int x,int l,int r,int L,int R){
if(L<=l && r<=R) return sum[x];
int mid=(l+r)>>1,ret=0;if(tag[x]) pushdown(x,mid-l+1,r-mid);
if(L<=mid) ret=(ret+query(x<<1,l,mid,L,R))%MOD;
if(mid<R) ret=(ret+query(x<<1|1,mid+1,r,L,R))%MOD;
return ret;
}
void updRange(int x){
while(top[x]!=1){
update(1,1,n,id[top[x]],id[x]);
x=fa[top[x]];
}
update(1,1,n,1,id[x]);
}
int qRange(int x){
int ret=0;
while(top[x]!=1){
ret=(ret+query(1,1,n,id[top[x]],id[x]))%MOD;
x=fa[top[x]];
}
ret=(ret+query(1,1,n,1,id[x]))%MOD;
return ret;
}
int main(){
n=rd(),Q=rd();int x,y,z;
for(int i=2;i<=n;i++){
x=rd()+1;add(x,i);add(i,x);
}
dfs1(1,0,1);dfs2(1,1);
for(int i=1;i<=Q;i++){
x=rd(),y=rd(),z=rd();y++;z++;
q[(i<<1)-1].id=i;q[(i<<1)-1].type=1;q[(i<<1)-1].pos=x;q[(i<<1)-1].z=z;
q[i<<1].id=i;q[i<<1].type=2;q[i<<1].pos=y;q[i<<1].z=z;
}
sort(q+1,q+1+(Q<<1));
for(int i=1;i<=(Q<<1);i++){
if(!q[i].pos) continue;
for(int j=q[i-1].pos+1;j<=q[i].pos;j++) updRange(j);
if(q[i].type==2) ans[q[i].id]+=qRange(q[i].z);
else ans[q[i].id]-=qRange(q[i].z);ans[q[i].id]%=MOD;
}
for(int i=1;i<=Q;i++)
printf("%d\n",(ans[i]+MOD)%MOD);
return 0;
}
BZOJ 3626: [LNOI2014]LCA(树剖+差分+线段树)的更多相关文章
- BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)
BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...
- 【小技巧】树剖套线段树优化建图如何做到 O(nlogn)
前提:用树剖套线段树优化树链连边.例题:bzoj4699 我们说树剖的时间复杂度是 $O(n\times log(n))$,是因为访问一条链时需要经过 $log(n)$ 级别条重链,对于每条重链还需要 ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- 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 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- BZOJ 3626 [LNOI2014]LCA ——树链剖分
思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...
- BZOJ 3307 雨天的尾巴 (树上差分+线段树合并)
题目大意:给你一棵树,树上一共n个节点,共m次操作,每次操作给一条链上的所有节点分配一个权值,求所有节点被分配到所有的权值里,出现次数最多的权值是多少,如果出现次数相同就输出最小的. (我辣鸡bzoj ...
- BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...
随机推荐
- HZOI2019SF
Simulation Final 坑.下午我要爆零(RP++) upd: 哈哈哈哈哈哈哈哈哈哈我真的爆零了哈哈哈哈哈哈哈哈哈哈 关于细节, T1A了但是和T3交反了哈哈哈哈哈哈哈哈哈哈 我说我真的不是 ...
- 【系统安全性】二、Web攻击与防范
二.Web攻击与防范 1.XSS攻击 跨站脚本攻击(Cross Site Scripting),因为简写CSS,与层叠样式表(Cascading Style Sheets)有歧义,所以取名XSS 原理 ...
- Golang 标准库提供的Log(一)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1405754 G ...
- ubuntu ceph集群安装以及简单使用
ubuntu ceph安装以及使用 1.安装环境 本文主要根据官方文档使用ubuntu14.04安装ceph集群,并且简单熟悉其基本操作.整个集群包括一个admin节点(admin node,主机名为 ...
- This inspection detects shadowing names defined in outer scopes.
错误信息:This inspection detects shadowing names defined in outer scopes. 检查到波浪处的单词已在函数外部定义. 解决:使用global ...
- JAVA的IO流下载音乐
public class DownloadMusic { private static int count = 1; public static void main(String[] args) th ...
- PHP面试 PHP基础知识 八(会话控制)
---恢复内容开始--- PHP会话控制技术 首先了解一下为什么要使用会话控制技术? 本身web 与服务器的交互是通过HTTP协议来实现的,而HTTP协议又是无状态协议.就是说明HTTP协议没有一个內 ...
- PHP面试 PHP基础知识 四(流程控制)
流程控制 PHP遍历数组的三种方式及各自的区别 三种方式:使用for循环.使用foreach循环.使用while.list().each()组合循环 区别:foe循环只能遍历索引数组,foeach可以 ...
- python_way day14 CSS,莫泰对话框
python_way day14 CSS 层叠样式表 一.CSS作用域: 二.css标签选择器 三.css样式 四.莫泰对话框: 一.css作用域: 基本用法:style="样式" ...
- Xen的半虚拟化(Paravirtualization)
三个特权级 IA-32体系提供了4个特权级别,正常情况下只用了2个, 操作系统运行在Ring 0,而应用程序运行在Ring 3. Xen让自己运行在Ring 0, 而操作系统运行在Ring 1, 应用 ...