【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
【BZOJ3626】LCA(树链剖分,Link-Cut Tree)
题面
Description
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
(即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)
Input
第一行2个整数n q。
接下来n-1行,分别表示点1到点n-1的父节点编号。
接下来q行,每行3个整数l r z。
Output
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
Sample Input
5 2
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题解
我不会做的一道神题
OrzZsyDalao,看一眼就会做
如果暴力求,,,还是挺好的呀
咳咳,看正解
画画图
对于区间L~R,把每个点到根节点的路径全部+1
此时累加Z到根节点的路径权值和,发现就是答案
为啥呢
首先,我们可以知道LCA一定在Z到根节点的路径上
其次,深度就是LCA到根节点的路径长度
如果像上面那样计算,因为整个路径上都加了1
相当于加了整个LCA的深度
因此这样做就是对的
所以,直接离线处理就好了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
#define lson (t[x].ch[0])
#define rson (t[x].ch[1])
#define MAX 100000
#define MOD 201314
inline int read()
{
int x=0,t=1;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=-1,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return x*t;
}
struct Node
{
int ch[2],ff;
int rev,pls;
int size,sum,v;
}t[MAX];
int S[MAX],top,n,Q;
bool isroot(int x){return t[t[x].ff].ch[0]!=x&&t[t[x].ff].ch[1]!=x;}
void pushup(int x)
{
t[x].size=t[t[x].ch[0]].size+t[t[x].ch[1]].size+1;
t[x].sum=(t[t[x].ch[0]].sum+t[t[x].ch[1]].sum+t[x].v)%MOD;
}
void Reverse(int x){swap(lson,rson);t[x].rev^=1;}
void pushdown(int x)
{
if(t[x].rev)
{
if(lson)Reverse(lson);
if(rson)Reverse(rson);
t[x].rev^=1;
}
if(t[x].pls)
{
if(lson)
{
(t[lson].v+=t[x].pls)%=MOD;
(t[lson].sum+=t[x].pls*t[lson].size%MOD)%=MOD;
t[lson].pls=(t[lson].pls+t[x].pls)%MOD;
}
if(rson)
{
(t[rson].v+=t[x].pls)%=MOD;
(t[rson].sum+=t[x].pls*t[rson].size%MOD)%=MOD;
t[rson].pls=(t[rson].pls+t[x].pls)%MOD;
}
t[x].pls=0;
}
}
void rotate(int x)
{
int y=t[x].ff,z=t[y].ff;
int k=t[y].ch[1]==x;
if(!isroot(y))t[z].ch[t[z].ch[1]==y]=x;t[x].ff=z;
t[y].ch[k]=t[x].ch[k^1];t[t[x].ch[k^1]].ff=y;
t[x].ch[k^1]=y;t[y].ff=x;
pushup(y);pushup(x);
}
void Splay(int x)
{
S[top=1]=x;
for(int i=x;!isroot(i);i=t[i].ff)S[++top]=t[i].ff;
while(top)pushdown(S[top--]);
while(!isroot(x))
{
int y=t[x].ff,z=t[y].ff;
if(!isroot(y))
(t[y].ch[1]==x)^(t[z].ch[1]==y)?rotate(x):rotate(y);
rotate(x);
}
}
void access(int x){for(int y=0;x;y=x,x=t[x].ff)Splay(x),t[x].ch[1]=y,pushup(x);}
void makeroot(int x){access(x);Splay(x);Reverse(x);}
void split(int x,int y){makeroot(x);access(y);Splay(y);}
void cut(int x,int y){split(x,y);t[y].ch[0]=t[x].ff=0;pushup(y);}
void link(int x,int y){makeroot(x);t[x].ff=y;}
struct Ask
{
int id,z,i,opt;
}q[MAX*2];
bool cmp(Ask a,Ask b){return a.i<b.i;}
int ans[MAX],tot;
int main()
{
n=read();Q=read();
for(int i=2;i<=n;++i)
{
int u=read()+1;
link(i,u);
}
for(int i=1;i<=Q;++i)
{
int l=read(),r=read()+1,z=read()+1;
++tot;q[tot].id=q[tot+1].id=i;
q[tot].z=q[tot+1].z=z;
q[tot].i=l;q[tot+1].i=r;
q[tot].opt=-1;q[++tot].opt=1;
}
sort(&q[1],&q[tot+1],cmp);
int pos=1;
while(!q[pos].i&&pos<tot)++pos;
for(int i=1;i<=n;++i)
{
split(i,1);
t[1].v=(t[1].v+1)%MOD;
t[1].sum=(t[1].sum+t[1].size)%MOD;
t[1].pls=(t[1].pls+1)%MOD;
while(q[pos].i==i&&pos<=tot)
{
split(q[pos].z,1);
ans[q[pos].id]=(ans[q[pos].id]+q[pos].opt*t[1].sum%MOD+MOD)%MOD;
++pos;
}
}
for(int i=1;i<=Q;++i)printf("%d\n",ans[i]%MOD);
return 0;
}
【BZOJ3626】LCA(树链剖分,Link-Cut Tree)的更多相关文章
- [BZOJ3626] [LNOI2014]LCA(树链剖分)
[BZOJ3626] [LNOI2014]LCA(树链剖分) 题面 给出一棵N个点的树,要求支持Q次询问,每次询问一个点z与编号为区间[l,r]内的点分别求最近公共祖先得到的最近公共祖先深度和.N, ...
- Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式)
Count on a tree SPOJ 10628 主席树+LCA(树链剖分实现)(两种存图方式) 题外话,这是我第40篇随笔,纪念一下.<( ̄︶ ̄)↗[GO!] 题意 是说有棵树,每个节点上 ...
- 【BZOJ2157】旅游(树链剖分,Link-Cut Tree)
[BZOJ2157]旅游(树链剖分,Link-Cut Tree) 题面 Description Ray 乐忠于旅游,这次他来到了T 城.T 城是一个水上城市,一共有 N 个景点,有些景点之间会用一座桥 ...
- Codeforces Round #329 (Div. 2) D. Happy Tree Party LCA/树链剖分
D. Happy Tree Party Bogdan has a birthday today and mom gave him a tree consisting of n vertecie ...
- 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次询问,每次询 ...
- [CodeVS2370] 小机房的树 (LCA, 树链剖分, LCT)
Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花 ...
- 洛谷P4482 [BJWC2018]Border 的四种求法 字符串,SAM,线段树合并,线段树,树链剖分,DSU on Tree
原文链接https://www.cnblogs.com/zhouzhendong/p/LuoguP4482.html 题意 给定一个字符串 S,有 q 次询问,每次给定两个数 L,R ,求 S[L.. ...
- 『LCA 树链剖分』
LCA Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根 的距离+1. 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公 ...
随机推荐
- 【笔记】h5 页面唤起电话呼叫
参考文章:https://www.cnblogs.com/lilin1995/p/5640684.html 最近完成一个公司的官网移动端页面,涉及到了唤起电话这个功能,说实在js 并没有为此提供 ap ...
- LeetCode - 307. Range Sum Query - Mutable
Given an integer array nums, find the sum of the elements between indices i and j (i ≤ j), inclusive ...
- 搭建简易的c语言与python语言CGI和Apache服务器的开发环境
搭建简易的c语言CGI和Apache服务器的开发环境 http://www.cnblogs.com/tt-0411/archive/2011/11/21/2257203.html python配置ap ...
- 中小研发团队架构实践之应用监控Metrics
一.Metrics简介 应用监控系统Metrics由Metrics.NET+InfluxDB+Grafana组合而成,通过客户端Metrics.NET在业务代码中埋点,Metrics.N ...
- 教我徒弟Android开发入门(二)
前言: 上一期实现了简单的QQ登录效果,这一期继续对上一期进行扩展 本期的知识点: Toast弹窗,三种方法实现按钮的点击事件监听 正文: Toast弹窗其实很简单,在Android Studio ...
- 利用Python爬取可用的代理IP
前言 就以最近发现的一个免费代理IP网站为例:http://www.xicidaili.com/nn/.在使用的时候发现很多IP都用不了. 所以用Python写了个脚本,该脚本可以把能用的代理IP检测 ...
- java中的Collection集合类
随着1998年JDK 1.2的发布,同时新增了常用的Collections集合类,包含了Collection和Map接口.而Dictionary类是在1996年JDK 1.0发布时就已经有了.它们都可 ...
- 高性能JavaScript读书笔记
零.组织结构 根据引言,作者将全书划分为四个部分: 一.页面加载js的最佳方式(开发前准备) 二.改善js代码的编程技巧(开发中) 三.构建与部署(发布) 四.发布后性能检测与问题追踪(线上问题优化) ...
- mybatis与spring的整合(使用sqlSession进行crud)
上次介绍了用接口的方法极大的节省了dao层,只需通过 配置文件和接口就可以实现,这次介绍的是通过splsession来实现dao,这种方法比较灵活: 先不说,上配置文件: 1.web.xml < ...
- Docker系列二:Docker的基本结构
Docker的基本结构 Docker 的三大基础组件 Docker有三个重要的概念:仓库 , 镜像 和 容器 ,它们是Docker的三大基出组件 Docker的组织结构 Docker处于操作系统和虚拟 ...