BZOJ 3626 [LNOI2014]LCA ——树链剖分
思路转化很巧妙。
首先把询问做差分。
然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和。
这样和原问题是等价的,然后树链剖分+线段树就可以做了。
#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define md 201314
#define maxn 100005 int n,q,dep[maxn],data[maxn],ans[maxn]; namespace SegTree{
int sum[maxn<<3],dsum[maxn<<3],tag[maxn<<3];
void update(int o)
{
sum[o]=(sum[o<<1]+sum[o<<1|1])%md;
}
void build(int o,int l,int r)
{
if (l==r)
{
sum[o]=tag[o]=0;
return ;
}
int mid=l+r>>1;
build(o<<1,l,mid); build(o<<1|1,mid+1,r);
update(o);
}
void pushdown(int o,int l,int r)
{
if (tag[o]!=0)
{
int mid=l+r>>1;
tag[o<<1]+=tag[o];tag[o<<1|1]+=tag[o];
sum[o<<1]+=tag[o]*(mid-l+1);
sum[o<<1|1]+=tag[o]*(r-mid);
tag[o]=0;
}
}
int querysum(int o,int l,int r,int L,int R)
{
if (L<=l&&r<=R) return sum[o];
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return querysum(o<<1,l,mid,L,R);
else if (L>mid) return querysum(o<<1|1,mid+1,r,L,R);
else return (querysum(o<<1,l,mid,L,R)+querysum(o<<1|1,mid+1,r,L,R))%md;
}
void modify(int o,int l,int r,int L,int R,int f)
{
if (L<=l&&r<=R)
{
sum[o]+=(r-l+1)*f;
tag[o]+=f;
return ;
}
pushdown(o,l,r);
int mid=l+r>>1;
if (R<=mid) return modify(o<<1,l,mid,L,R,f),update(o);
else if (L>mid) return modify(o<<1|1,mid+1,r,L,R,f),update(o);
else return modify(o<<1,l,mid,L,R,f),modify(o<<1|1,mid+1,r,L,R,f),update(o);
}
} namespace Tree{
int h[maxn],to[maxn],ne[maxn],en=0;
int siz[maxn],son[maxn],dfn[maxn],top[maxn],fa[maxn],tot;
int pos[maxn],id[maxn];
vector < pair<int,int> > v[maxn];
void add(int a,int b)
{
to[en]=b;ne[en]=h[a];h[a]=en++;
}
void dfs1(int o)
{
siz[o]=1;
for (int i=h[o];i>=0;i=ne[i])
{
dep[to[i]]=dep[o]+1;
fa[to[i]]=o;
dfs1(to[i]);
siz[o]+=siz[to[i]];
if (siz[to[i]]>siz[son[o]]) son[o]=to[i];
}
}
void dfs2(int o,int tp)
{
top[o]=tp;pos[o]=++tot;id[tot]=o;
if (!son[o]) return;
dfs2(son[o],tp);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=son[o]) dfs2(to[i],to[i]);
return ;
}
void build()
{
F(i,1,n) data[i]=dep[id[i]];
SegTree::build(1,1,n);
}
void add(int a,int b,int f)
{
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
SegTree::modify(1,1,n,pos[top[a]],pos[a],f);
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
SegTree::modify(1,1,n,pos[b],pos[a],f);
}
int query(int a,int b)
{
int ret=0;
while (top[a]!=top[b])
{
if (dep[top[a]]<dep[top[b]]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[top[a]],pos[a]);
ret%=md;
a=fa[top[a]];
}
if (dep[a]<dep[b]) swap(a,b);
ret+=SegTree::querysum(1,1,n,pos[b],pos[a]);
return ret%md;
}
void work()
{
F(i,1,q)
{
int l,r,z; scanf("%d%d%d",&l,&r,&z);l++;r++;z++;
v[l-1].push_back(mp(z,-i));
v[r].push_back(mp(z,i));
}
F(i,1,n)
{
add(1,i,1);
for (int j=0;j<v[i].size();++j)
{
pair<int,int> pa=v[i][j];
if (pa.second<0) ans[-pa.second]-=query(1,pa.first);
else ans[pa.second]+=query(1,pa.first);
}
}
F(i,1,q) printf("%d\n",(ans[i]+md)%md);
}
} namespace Graph{
int h[maxn],to[maxn],ne[maxn],en=0;
void add(int a,int b)
{to[en]=b;ne[en]=h[a];h[a]=en++;}
void dfs(int o,int fa)
{
if (fa) Tree::add(fa,o);
for (int i=h[o];i>=0;i=ne[i])
if (to[i]!=fa) dfs(to[i],o);
}
} int main()
{
scanf("%d%d",&n,&q);
memset(Tree::h,-1,sizeof Tree::h);
memset(Graph::h,-1,sizeof Graph::h);
F(i,2,n)
{
int fa; scanf("%d",&fa);
Graph::add(fa+1,i);
}
Graph::dfs(1,0);
dep[1]=1;
Tree::dfs1(1);
Tree::dfs2(1,1);
Tree::build();
Tree::work();
}
BZOJ 3626 [LNOI2014]LCA ——树链剖分的更多相关文章
- BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线
http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...
- 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 ...
- [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 树链剖分+线段树
题目描述 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q次询问,每次询 ...
- bzoj3626 [LNOI2014]LCA——树链剖分
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3626 思路很巧妙,把区间换成前缀和相减: 把 l ~ r 到根路径上的点的点权都+1,然后 ...
- [LNOI2014]LCA(树链剖分)
BZOJ传送门 Luogu传送门 题目:给你一棵树,给你n个询问,每个询问要求输出$\sum_{i=l}^{r}depth(LCA(i,z))$ 细看看其实没有想象的那么难 大体思路: 1.对于每个询 ...
随机推荐
- 使用Selennium实现短信轰炸机
前言 可以用来轰炸一下骗子,但最好不要乱用.本来初学Python,仅当学习. selenium和ChromeDriver的安装与配置 可参考这篇博客,这里不再赘述. 程序实现 短信轰炸机的原理是利用一 ...
- MVC和MVP到底有什么区别呢?
MVC和MVP到底有什么区别呢? MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写 MVP 全称:Model-V ...
- 虚拟机设置NAT
需要开启虚拟机网络相关服务, 安装虚拟网卡, 还有必须安装 VMware Tools VMware虚拟机下实现NAT方式上网1. 把你的虚拟网卡VMnet8设置为自动获得IP.自动获得DNS服务器,启 ...
- 使用虚拟环境来管理python的包
1.背景 在开发python项目的过程中,我们会用到各种各样的包,我们使用pip来管理包,请看下图我们刚装好python解释器时已安装的包: 但是随着我们疯狂的使用pip install xxx后,系 ...
- CF-1013 (2019/02/09 补)
CF-1013 A. Piles With Stones 比较两个序列的和,因为只能拿走或者不拿,所以总数不能变大. B. And 答案只有 -1,0,1,2几种可能,所以对于每一种答案都暴力扫一次是 ...
- 【费用流】 ICPC 2016 China Final J. Mr.Panda and TubeMaster
表示“必须选”的模型 题目大意 题目分析 一个格子有四种方式看上去很难处理.将横竖两个方向分开考虑,会发现:因为收益只与相邻格子是否连通有关,所以可以将一个格子拆成表示横竖两个方向的,互相独立的点. ...
- Linux - 链接概念详解
1> Linux链接概念Linux链接分两种,一种被称为硬链接(Hard Link),另一种被称为符号链接(Symbolic Link).默认情况下,ln命令产生硬链接. [硬连接]硬连接指通过 ...
- C++:100阶乘数组输出
#include <iostream> using namespace std; int main(){ int i =1; int a[2048]={0}; while(i !=101) ...
- 事务控制语言DTL
一.什么是事务? · 数据库中的事务,是指可以将“多条相关语句执行”看做是“一条语句执行”的一种内部机制.即事务是一种可以保证“多条语句一次性执行完成”或者一条语句都不执行的机制. 三.事务的特点 原 ...
- mysql按指定顺序排序
select id,name from htms_center_freight_users where id in(114,112,91,223,134) order by find_in_set(i ...