BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626
直接引用清华爷gconeice的题解吧
显然,暴力求解的复杂度是无法承受的。
考虑这样的一种暴力,我们把 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<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int maxn=;
const long long modn=;
const long long minf=<<;
int n,m;
struct nod{
int y,next;
}e[maxn];int head[maxn]={},tot=;
int fa[maxn]={},top[maxn]={},pos[maxn]={},kid[maxn]={},dep[maxn]={};
void init(int x,int y){
e[++tot].y=y;e[tot].next=head[x];head[x]=tot;
}
int dfs1(int x){
int y,hug=,siz,tsn=;dep[x]=dep[fa[x]]+;
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==fa[x])continue;
siz=dfs1(y);
if(siz>hug)hug=siz,kid[x]=y;
tsn+=siz;
}return tsn;
}
void dfs2(int x,int pa){
int y;top[x]=pa;pos[x]=++tot;
if(kid[x])dfs2(kid[x],pa);
for(int i=head[x];i;i=e[i].next){
y=e[i].y;
if(y==kid[x]||y==fa[x])continue;
dfs2(y,y);
}
}
struct seg{
long long sum,w,l,r;
seg(){sum=l=r=;}
}t[maxn*];
void build(int x,int l,int r){
t[x].l=l;t[x].r=r;
if(l==r)return;
int mid=(l+r)/;
build(x*,l,mid);
build(x*+,mid+,r);
}
void pushup(int x){
if(t[x].r>t[x].l)t[x].sum=t[x*].sum+t[x*+].sum;
t[x].sum+=(t[x].r-t[x].l+)*t[x].w;
}
void add(int x,int l,int r){
if(l<=t[x].l&&t[x].r<=r){
if(t[x].l==t[x].r)t[x].sum+=;
else {t[x].w+=;pushup(x);}
return;
}
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;
if(r>mid) add(rs,l,r);
if(l<=mid) add(ls,l,r);
pushup(x);
}
long long sum(int x,int l,int r,int w){
if(l<=t[x].l&&t[x].r<=r)return t[x].sum+w*(t[x].r-t[x].l+);
int mid=(t[x].l+t[x].r)/,ls=x*,rs=x*+;long long tsn=;
if(l<=mid) tsn+=sum(ls,l,r,w+t[x].w);
if(r>mid) tsn+=sum(rs,l,r,w+t[x].w);
return tsn;
}
long long doit(int x){
int a=top[x];long long tsn=;
for(;a!=;){
tsn+=sum(,pos[a],pos[x],);
x=fa[a];a=top[x];
}
tsn+=sum(,pos[a],pos[x],);
return tsn;
}
void datup(int x){
int a=top[x];
for(;a!=;){
add(,pos[a],pos[x]);
x=fa[a];a=top[x];
}
add(,pos[a],pos[x]);
}
struct lcc{
int num;
int z;int id;
long long ans;
}q[maxn*];
bool cmp1(lcc aa,lcc bb){return aa.num<bb.num;}
bool cmp2(lcc aa,lcc bb){return aa.id<bb.id;}
int main(){
scanf("%d%d",&n,&m);
int x,y,z;
for(int i=;i<n;i++){
scanf("%d",&y);
init(y+,i+);
fa[i+]=y+;
}tot=;dfs1();dfs2(,);build(,,n);tot=;
for(int j=;j<=m;j++){
scanf("%d%d%d",&x,&y,&z);
x++;y++;z++;
if(y<x)swap(x,y);
q[++tot].num=x-;q[tot].z=z;q[tot].id=tot;
q[++tot].num=y;q[tot].z=z;q[tot].id=tot;
}sort(q+,q++tot,cmp1);
int now=;
for(int i=;i<=tot;i++){
while(now<q[i].num){
now++;datup(now);
}
q[i].ans=doit(q[i].z);
}
sort(q+,q++tot,cmp2);
for(int i=;i<=m;i++){
long long z=(q[i*].ans-q[i*-].ans)%;
printf("%lld\n",z);
}
return ;
}
BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线的更多相关文章
- 【bzoj3626】[LNOI2014]LCA 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- BZOJ.1036 [ZJOI2008]树的统计Count ( 点权树链剖分 线段树维护和与最值)
BZOJ.1036 [ZJOI2008]树的统计Count (树链剖分 线段树维护和与最值) 题意分析 (题目图片来自于 这里) 第一道树链剖分的题目,谈一下自己的理解. 树链剖分能解决的问题是,题目 ...
- BZOJ 3672[NOI2014]购票(树链剖分+线段树维护凸包+斜率优化) + BZOJ 2402 陶陶的难题II (树链剖分+线段树维护凸包+分数规划+斜率优化)
前言 刚开始看着两道题感觉头皮发麻,后来看看题解,发现挺好理解,只是代码有点长. BZOJ 3672[NOI2014]购票 中文题面,题意略: BZOJ 3672[NOI2014]购票 设f(i)f( ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
- bzoj 4196 [Noi2015]软件包管理器 (树链剖分+线段树)
4196: [Noi2015]软件包管理器 Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 2852 Solved: 1668[Submit][Sta ...
- bzoj 2157: 旅游【树链剖分+线段树】
裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio& ...
- BZOJ 3589 动态树 (树链剖分+线段树)
前言 众所周知,90%90\%90%的题目与解法毫无关系. 题意 有一棵有根树,两种操作.一种是子树内每一个点的权值加上一个同一个数,另一种是查询多条路径的并的点权之和. 分析 很容易看出是树链剖分+ ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
随机推荐
- fetch and js异步介绍
http://www.ruanyifeng.com/blog/2012/12/asynchronous%EF%BC%BFjavascript.html Javascript异步编程的4种方法 ht ...
- IntelliJ Idea key shortcuts
>Default explaination Official IntelliJ Idea 常用快捷键列表 Shortcuts Ctrl+Shift + Enter,语句完成 "!&qu ...
- Let's Encrypt 免费通配 https 签名证书 安装方法2 ,安卓签名无法认证!
Let's Encrypt 免费通配 https 签名证书 安装方法 按照上文 配置完毕后你会发现 在pc浏览器中正常访问,在手机浏览器中无法认证 你只需要安装一个或多个中级证书 1.查看Nginx ...
- 在eclipse安装mybatis的插件
1.在help中打开 2.搜索mybatipse 3:功能简介 1:要查找某一个方法 在dao接口中某一个方法中 按住 Ctrl键 鼠标指到方法名称上 选择open xml 就会自动跳转 ...
- apache2启动失败(Failed to start The Apache HTTP Server.)解决方案
不知道如何启动apache2就启动不来了. 如下图所示: 即使卸载了重新装也是如此 经过测试卸载并清除软件包的配置即可解决 sudo apt-get purge apache2 sudo apt-g ...
- 继电器是如何成为CPU的(1)【转】
转自:http://www.cnblogs.com/bitzhuwei/p/from_relay_to_tiny_CPU.html 阅读目录(Content) 从电池.开关和继电器开始 用继电器做个与 ...
- Appium环境搭建说明(包括报错处理)
Appium环境搭建说明 一.环境配置 前提是windows系统已安装以下软件: 1.jdk 我装的是1.8.0 2.android-sdk 3.python,3.4-3.6 5.Node.js,v8 ...
- css预处理scss环境配置
css 预处理器 CSS 预处理器用一种专门的编程语言,进行 Web css编码,然后再编译成正常的 CSS 文件,以供项目使用:说简单点就是在某个环境下写css 可以写变量.表达式.嵌套等,在通过该 ...
- js中startWith、endWith 函数不能在任何浏览器兼容的问题
在做js测试的时候用到了startsWith函数,但是他并不是每个浏览器都有的,所以我们一般要重写一下这个函数,具体的用法可以稍微总结一下 在有些浏览器中他是undefined 所以我们可以这样的处理 ...
- Codefroces 919D Substring(拓扑排序+DP)
题目链接:http://codeforces.com/problemset/problem/919/D 题目大意:给你一张有向图,给你每个顶点上的字母和一些边,让你找出一条路径,路径上的相同字母数最多 ...