bzoj3626 [LNOI2014]LCA——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626
思路很巧妙,把区间换成前缀和相减;
把 l ~ r 到根路径上的点的点权都+1,然后 z 到根求和,就是 z 与 l ~ r 每个点 lca 深度的和;
这里若要用前缀和,则需要把询问离线排序;
然后上树链剖分,修改和求和线段树解决即可。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=,mod=;
int n,m,fa[maxn],head[maxn],ct,dfn[maxn],tim;
int top[maxn],to[maxn],siz[maxn],tl[maxn],tr[maxn];
struct N{
int to,next;
N(int t=,int n=):to(t),next(n) {}
}edge[maxn<<];
struct T{ll s,lzy,size;}t[maxn<<];
struct Q{int l,r,z,bh;ll ansl,ansr;}q[maxn];
void add(int x,int y){edge[++ct]=N(y,head[x]);head[x]=ct;}
bool cmp(int x,int y){return q[x].l<q[y].l;}
bool cmp2(int x,int y){return q[x].r<q[y].r;}
int rd()
{
int ret=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
return ret;
}
void dfs(int x,int f)
{
siz[x]=;
for(int i=head[x];i;i=edge[i].next)
{
int u=edge[i].to;
if(u==f)continue;
dfs(u,x); siz[x]+=siz[u];
if(siz[u]>siz[to[x]])to[x]=u;
}
}
void dfs2(int x)
{
dfn[x]=++tim;
if(to[x])top[to[x]]=top[x],dfs2(to[x]);
for(int i=head[x];i;i=edge[i].next)
{
int u=edge[i].to;
if(u==fa[x]||u==to[x])continue;
top[u]=u; //top[u]!=x !!!
dfs2(u);
}
}
void pushup(int x)
{
t[x].size=t[x<<].size+t[x<<|].size;
t[x].s=t[x<<].s+t[x<<|].s;
}
void pushdown(int x)
{
if(!t[x].lzy)return;
int ls=(x<<),rs=(x<<|);
ll l=t[x].lzy;t[x].lzy=;
t[ls].s+=l*t[ls].size; t[ls].lzy+=l;
t[rs].s+=l*t[rs].size; t[rs].lzy+=l;
}
void build(int x,int l,int r)
{
if(l==r){t[x].size=; return;}
int mid=((l+r)>>);
build(x<<,l,mid); build(x<<|,mid+,r);
pushup(x);
}
void update(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)
{
t[x].s+=t[x].size; t[x].lzy++;
return;
}
pushdown(x);
int mid=((l+r)>>);
if(mid>=L)update(x<<,l,mid,L,R);
if(mid<R)update(x<<|,mid+,r,L,R);
pushup(x);
}
void work(int x)//x 到 rt 路径上点权+1
{
while(x)
{
update(,,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
// update(1,1,n,dfn[rt],dfn[rt]);
}
ll query(int x,int l,int r,int L,int R)
{
if(l>=L&&r<=R)return t[x].s;
int mid=((l+r)>>); ll ret=;
pushdown(x);
if(mid>=L)ret+=query(x<<,l,mid,L,R);
if(mid<R)ret+=query(x<<|,mid+,r,L,R);
return ret;
}
ll qry(int x)
{
ll ret=;
while(x)
{
ret+=query(,,n,dfn[top[x]],dfn[x]);
x=fa[top[x]];
}
return ret;
}
int main()
{
n=rd();m=rd();
for(int i=;i<=n;i++){fa[i]=rd()+; add(fa[i],i); add(i,fa[i]);}
for(int i=;i<=m;i++)
{
q[i].l=rd()+; q[i].r=rd()+; q[i].z=rd()+;
tl[i]=i; tr[i]=i;
}
sort(tl+,tl+m+,cmp);
sort(tr+,tr+m+,cmp2);
dfs(,); top[]=; dfs2(); build(,,n);
int dl=,dr=;
while(q[tl[dl]].l==)dl++;
for(int i=;i<=n;i++)
{
work(i);
while(q[tl[dl]].l-==i&&dl<=m)
{
q[tl[dl]].ansl=qry(q[tl[dl]].z);//不套 dfn !!!
dl++;
}
while(q[tr[dr]].r==i&&dr<=m)
{
q[tr[dr]].ansr=qry(q[tr[dr]].z);
dr++;
}
}
for(int i=;i<=m;i++)
printf("%lld\n",(q[i].ansr-q[i].ansl)%mod);
return ;
}
bzoj3626 [LNOI2014]LCA——树链剖分的更多相关文章
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- BZOJ3626[LNOI2014]LCA——树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- BZOJ3626 [LNOI2014]LCA 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ3626 题意概括 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节 ...
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先. ...
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- 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 (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
随机推荐
- Go切片的操作
package main import "fmt" //切片的操作 func main() { //创建slice var s []int //zero value for sli ...
- 查看java进程中哪个线程在消耗系统资源
1 top -p $pid -H 加上-H这个参数后,会列出有哪些线程.这样就可以看到哪个线程id最消耗系统资源了.看到的线程id是10进制的数字. 2 jstack $pid 可以打印出制定jav ...
- ZOJ 2588 求割边问题
题目链接:http://vjudge.net/problem/viewProblem.action?id=14877 题目大意: 要尽可能多的烧毁桥,另外还要保证图的连通性,问哪些桥是绝对不能烧毁的 ...
- HDU1272 迷宫通路数
Problem Description 上次Gardon的迷宫城堡小希玩了很久(见Problem B),现在她也想设计一个迷宫让Gardon来走.但是她设计迷宫的思路不一样,首先她认为所有的通道都应该 ...
- tree(poj 1741)
题意:给一颗n个节点的树,每条边上有一个距离v(v<=1000).定义d(u,v)为u到v的最小距离.给定k值,求有多少点对(u,v)使u到v的距离小于等于k. /* 照着点分治模板敲了敲,有很 ...
- linux 常见名词及命令(二)
pwd 用于显示当前的工作目录. cd 用于切换工作路径 cd - 切换到上一次的目录 cd ~ 切换到家目录 cd ~username 切换到其他用户的家目录 cd .. 切换到上级目录 ls 用于 ...
- js命名
JS变量名前加 _ 与 $ 的区别: 下划线一般当做私有属性, 业界会比较常用$开头作为框架.库的关键词前缀,目的是避免命名冲突
- POJ 2135 最小费用最大流 入门题
Farm Tour Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 19207 Accepted: 7441 Descri ...
- Ansible 详细用法说明(一)
一.概述 运维工具按需不需要有代理程序来划分的话分两类: agent(需要有代理工具):基于专用的agent程序完成管理功能,puppet, func, zabbix agentless(无须代理工具 ...
- hdu1042 (模拟n!)
题目大意: 求 n.(可能会超过整数范围,这里用数组模拟n!的值) pid=1042">http://acm.hdu.edu.cn/showproblem.php?pid=1042 A ...