[LNOI2014]LCA 树链剖分 离线 前缀和 思维题
题目描述:
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求
$\sum_{l\leq i\leq r} dep[LCA(i,z)]$
题解:
$1$. 这个问题看起来很麻烦,我们不难发现 $dep[LCA(i,z)]\geq dep[z]$,这是显然的。
$2$. 而我们还会发现我们要求的结果可以转化为将 $z$ 到根节点的边权全部置为 1,$l<=i<=r$ 中每个点到根节点的路径和。
$3$. 下一步,我们有不难看出这个操作是可逆的。即我们可以将 $l\leq i\leq r$ 中所有点到根节点之间的边权都 $+1$,求$z$到根节点的路径和。
$4$. 还可以看出,对于同一个 $t$,答案可以转化为 $ans(1,r)-ans(1,l-1)$。
综上,我们可以将每个询问拆成2个询问(分别询问 $l-1$ 和 $r$),并按照下标进行排序。
一边更新一边进行查询即可。
Code:
#include<cstdio>
#include<algorithm>
#include<string>
#include<iostream>
#include<cstring>
using namespace std;
void setIO(string a){
freopen((a+".in").c_str(),"r",stdin);
}
const int maxn=200000;
const int mod=201314;
int n,q;
int dep[maxn],top[maxn],son[maxn],A[maxn],fa[maxn];
struct Get_Tree{
int cnt,cnt2;
int nex[maxn],to[maxn],head[maxn],siz[maxn];
void add_edge(int u,int v){
nex[++cnt]=head[u];
head[u]=cnt;
to[cnt]=v;
}
void dfs1(int u,int depth){
dep[u]=depth;
siz[u]=1;
for(int v=head[u];v;v=nex[v]){
dfs1(to[v],depth+1);
siz[u]+=siz[to[v]];
if(!son[u]||siz[to[v]]>siz[son[u]]) son[u]=to[v];
}
}
void dfs2(int u,int tp){
top[u]=tp;
A[u]=++cnt2;
if(son[u])dfs2(son[u],tp);
for(int v=head[u];v;v=nex[v])
if(to[v]!=son[u])dfs2(to[v],to[v]);
}
void solve(){
dfs1(1,1);
dfs2(1,1);
}
}tree;
struct Segment_Tree{
#define lson (o<<1)
#define rson (o<<1)|1
int sumv[maxn<<2],lazy[maxn<<2];
void pushdown(int l,int r,int o){
if(lazy[o]){
int mid=(l+r)>>1;
sumv[lson]+=(mid-l+1)*lazy[o];
sumv[rson]+=(r-mid)*lazy[o];
lazy[lson]+=lazy[o];
lazy[rson]+=lazy[o];
sumv[lson]%=mod;
sumv[rson]%=mod;
lazy[lson]%=mod;
lazy[rson]%=mod;
lazy[o]=0;
}
}
void pushup(int o){
sumv[o]=sumv[lson]+sumv[rson];
}
void update(int l,int r,int L,int R,int k,int o){
if(l>r||l>R||r<L)return;
if(l>=L && r<=R){
sumv[o]+=(r-l+1)*k;
lazy[o]+=k;
sumv[o]%=mod;
lazy[o]%=mod;
return;
}
int mid=(l+r)>>1;
pushdown(l,r,o);
update(l,mid,L,R,k,lson);
update(mid+1,r,L,R,k,rson);
pushup(o);
}
int query(int l,int r,int L,int R,int o){
if(l>r||l>R||r<L)return 0;
if(l>=L&&r<=R) return sumv[o];
int mid=(l+r)>>1;
pushdown(l,r,o);
return (long long)(query(l,mid,L,R,lson)+query(mid+1,r,L,R,rson))%mod;
}
int look_up(int x){
int val=0;
while(x){
val+=query(1,n,A[top[x]],A[x],1);
val%=mod;
x=fa[top[x]];
}
return val;
}
void modify(int x){
while(x){
update(1,n,A[top[x]],A[x],1,1);
x=fa[top[x]];
}
}
}T;
struct Ask{
int pos,idx,node,o;
Ask(int pos=0,int idx=0,int node=0,int o=0):pos(pos),idx(idx),node(node),o(o){}
}ask[maxn];
int asks=0;
void Read(){
int f;
scanf("%d%d",&n,&q);
for(int i=2;i<=n;++i){
scanf("%d",&f);
fa[i]=f+1;
tree.add_edge(f+1,i);
}
for(int i=1;i<=q;++i){
int l,r,z;
scanf("%d%d%d",&l,&r,&z);
ask[++asks]=Ask(l-1+1,i,z+1,-1);
ask[++asks]=Ask(r+1,i,z+1,1);
}
}
int fin[maxn];
bool cmp(Ask i,Ask j){
return i.pos<j.pos;
}
void solve(){
tree.solve();
sort(ask+1,ask+1+asks,cmp);
int cur=0;
for(int i=1;i<=asks;++i){
while(cur<ask[i].pos){
T.modify(cur+1);
cur+=1;
}
fin[ask[i].idx]+=T.look_up(ask[i].node)*ask[i].o;
}
for(int i=1;i<=q;++i)printf("%d\n",(fin[i]%mod+mod)%mod);
} int main(){
Read();
solve();
return 0;
}
[LNOI2014]LCA 树链剖分 离线 前缀和 思维题的更多相关文章
- 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了... -------------------------------------------------------------- ...
- 洛谷 P4211 [LNOI2014]LCA (树链剖分+离线)
题目:https://www.luogu.org/problemnew/solution/P4211 相当难的一道题,其思想难以用言语表达透彻. 对于每个查询,区间[L,R]中的每个点与z的lca肯定 ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- 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 ...
随机推荐
- TortoiseGit连接github.com
1.下载两个软件:msysgit,TortoiseGit 2.先安装msysgit,再安装TortoiseGit,安装过程保持默认即可. 3.为了安全,我们需要使ssh key.开始菜单--Torto ...
- 根据ip地址获取城市
var ip=context.Request.UserHostAddress; string url = "http://int.dpool.sina.com.cn/iplookup/ipl ...
- Git 环境安装
本文环境: 操作系统:Windows XP SP3 Git客户端:TortoiseGit-1.8.14.0-32bit 一.安装Git客户端 全部安装均采用默认! 1. 安装支撑软件 msysgit: ...
- Web前端为什么这么火爆?
Web前端为什么这么火爆? 互联网发展到今天,全球已有28.9亿互联网用户,中国有355万网站,6.5亿网民,13亿手机用户,5亿微信用户,当步入互联网+时代后,互联网已经越来越复杂,纷繁复杂的互联网 ...
- 爬虫来啦!Day91
# 一.爬虫# 1.基本操作# 排名爬虫刷票# 抽屉网的所有发布新闻点赞# 自动化程序模拟用于的日常操作# 投票的机制是利用cookies,禁用cookies模式# 自定义的异步IO模块就是Socke ...
- select选中值,传this
<select onChange = "a(this)"></select> function a(obj){ $(obj).find("opti ...
- NodeJS学习笔记 (5)网络服务-http-req(ok)
原文:https://github.com/chyingp/nodejs-learning-guide 自己敲代码: 概览 本文的重点会放在req这个对象上.前面已经提到,它其实是http.Incom ...
- luogu 4844 LJJ爱数数 (莫比乌斯反演+数学推导)
题目大意:求满足gcd(a,b,c)==1,1/a+1/b=1/c,a,b,c<=n的{a,b,c}有序三元组个数 因为题目里有LJJ我才做的这道题 出题人官方题解https://www.cnb ...
- 【python爬虫和正则表达式】爬取表格中的的二级链接
开始进公司实习的一个任务是整理一个网页页面上二级链接的内容整理到EXCEL中,这项工作把我头都搞大了,整理了好几天,实习生就是端茶送水的.前段时间学了爬虫,于是我想能不能用python写一个爬虫一个个 ...
- Matlab 图像的邻域和块操作
图像的邻域操作是指输出图像的像素点取值,由输入图像的某个像素点及其邻域内的像素,通常像素点的邻域是一个远小于图像本身尺寸.形状规则的像素块,如2×2,3×3正方形.2×3矩形等,或者近似圆形的多边形. ...