3626: [LNOI2014]LCA

Time Limit: 10 Sec  Memory Limit: 128 MB

Submit: 1266  Solved: 448

[Submit][Status][

id=3626" style="color:blue; text-decoration:none">Discuss]

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。

Source

这道题思路非常好!

假设把x到根的权值所有加1。那么y到根的权值和就添加dep[lca(x,y)]。

扩展到区间,假设把[l,r]的点到根的权值所有加1,那么z到根的权值和就添加∑(l≤i≤r)dep[lca(i,z)]。

那么对于每个(l,r,z)的询问。我们就能够拆成两个前缀和来离线处理了。

链查询,树链剖分+线段树。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define maxn 50005
#define mod 201314
using namespace std;
struct edge{int next,to;}e[maxn];
struct seg{int l,r,sum,tag;}t[maxn*4];
struct data{int next,z,pos,tag;}g[maxn*2];
int n,m,cnt,tot;
int p[maxn],sz[maxn],fa[maxn],son[maxn],ans[maxn];
int head[maxn],belong[maxn];
inline int read()
{
int x=0,f=1;char ch=getchar();
while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
inline void add_edge(int x,int y)
{
e[++cnt]=(edge){head[x],y};head[x]=cnt;
}
inline void add_data(int x,int y,int num,int tg)
{
g[++cnt]=(data){head[x],y,num,tg};head[x]=cnt;
}
inline void dfs1(int x)
{
sz[x]=1;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
fa[y]=x;
dfs1(y);
sz[x]+=sz[y];
if (sz[y]>sz[son[x]]) son[x]=y;
}
}
inline void dfs2(int x,int chain)
{
belong[x]=chain;p[x]=++tot;
if (son[x]) dfs2(son[x],chain);
for(int i=head[x];i;i=e[i].next)
if (e[i].to!=son[x]) dfs2(e[i].to,e[i].to);
}
inline void update(int k,int z)
{
t[k].sum+=z*(t[k].r-t[k].l+1);
t[k].tag+=z;
}
inline void pushdown(int k)
{
if (!t[k].tag) return;
update(k<<1,t[k].tag);update(k<<1|1,t[k].tag);
t[k].tag=0;
}
inline void pushup(int k)
{
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
inline void build(int k,int l,int r)
{
t[k].l=l;t[k].r=r;t[k].sum=0;
if (l==r) return;
int mid=(l+r)>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
}
inline int query(int k,int x,int y)
{
if (t[k].l==x&&t[k].r==y) return t[k].sum;
int mid=(t[k].l+t[k].r)>>1;
pushdown(k);
if (y<=mid) return query(k<<1,x,y);
else if (x>mid) return query(k<<1|1,x,y);
else return query(k<<1,x,mid)+query(k<<1|1,mid+1,y);
}
inline void add(int k,int x,int y,int z)
{
if (t[k].l==x&&t[k].r==y){update(k,z);return;}
int mid=(t[k].l+t[k].r)>>1;
pushdown(k);
if (y<=mid) add(k<<1,x,y,z);
else if (x>mid) add(k<<1|1,x,y,z);
else add(k<<1,x,mid,z),add(k<<1|1,mid+1,y,z);
pushup(k);
}
inline void solveadd(int x)
{
while (belong[x]!=1)
{
add(1,p[belong[x]],p[x],1);
x=fa[belong[x]];
}
add(1,p[1],p[x],1);
}
inline int solvesum(int x)
{
int sum=0;
while (belong[x]!=1)
{
sum+=query(1,p[belong[x]],p[x]);
x=fa[belong[x]];
}
sum+=query(1,p[1],p[x]);
return sum;
}
int main()
{
n=read();m=read();
F(i,2,n) add_edge(read()+1,i);
dfs1(1);dfs2(1,1);
build(1,1,n);
cnt=tot=0;
memset(head,0,sizeof(head));
F(i,1,m)
{
int l=read()+1,r=read()+1,z=read()+1;
add_data(l-1,z,i,-1);add_data(r,z,i,1);
}
F(i,1,n)
{
solveadd(i);
for(int j=head[i];j;j=g[j].next)
ans[g[j].pos]+=solvesum(g[j].z)*g[j].tag;
}
F(i,1,m) printf("%d\n",ans[i]%mod);
}

bzoj3626【LNOI2014】LCA的更多相关文章

  1. 【LNOI2014】LCA

    题面 题解 考察\(dep[\mathrm{LCA}(i, x)]\)的性质,发现它是\(i\)和\(x\)的链交的长度. 那么对每个\(i\)所在的链打一个区间加标记,询问时算一下\(x\)所在的链 ...

  2. 【LNOI2014】【BZOJ3626】NOIp2018模拟(三) LCA

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设$dep[i]$表示点i的深度,$lca(i,j)$表示i与j的最近公共祖 ...

  3. 【P4211 LNOI2014】LCA——树链剖分 +询问离线

    (7.16晚)更完先在B站颓一会儿-- --------------------------------------------------------------- (以下为luogu题面) 题目描 ...

  4. 【Homework】LCA&RMQ

    我校是神校,作业竟然选自POJ,难道不知道“珍爱生命 勿刷POJ”么? 所有注明模板题的我都十分傲娇地没有打,于是只打了6道题(其实模板题以前应该打过一部分但懒得找)(不过感觉我模板还是不够溜要找个时 ...

  5. 【模板】LCA

    代码如下 #include <bits/stdc++.h> using namespace std; const int maxn=5e5+10; inline int read(){ i ...

  6. 【模板】Lca倍增法

    Codevs 1036 商务旅行 #include<cstdio> #include<cmath> #include<algorithm> using namesp ...

  7. 【HNOI2015】开店

    题面 题解 树链剖分 + 主席树 先考虑一个简单一点的问题: [LNOI2014]LCA 我们考察\(dep[\mathrm{LCA}(i, x)]\)的性质,发现它是\(i\)和\(x\)的链交的长 ...

  8. 【51nod】1766 树上的最远点对

    [题意]给定n个点的树,m次求[a,b]和[c,d]中各选出一个点的最大距离.abcd是标号区间,n,m<=10^5 [算法]LCA+树的直径理论+线段树 [题解] 树的直径性质:距离树上任意点 ...

  9. 【BZOJ】1776: [Usaco2010 Hol]cowpol 奶牛政坛

    [题意]给定n个点的树,每个点属于一个分类,求每个分类中(至少有2个点)最远的两点距离.n<=200000 [算法]LCA [题解]结论:树上任意点集中最远的两点一定包含点集中深度最大的点(求树 ...

随机推荐

  1. [SharePoint2010开发入门经典]9创建更好的用户体验----silverlight

    本章概要: 1.了解Silverlight 2.理解为什么使用Silverlight 3.介绍如何集成SharePoint和Silverlight

  2. C++表达式求值(利用数据结构栈)

    唉,刚刚用C++又又一次写了一个较完好的表达式求值程序,最后精简后程序还不到100行.这不经让我 想到了大一上学期刚学c语言时自己费了好大的劲,写了几百行并且功能还不是非常齐全(当时还不能计算有括号的 ...

  3. Share Your Knowledge and Experiences

     Share Your Knowledge and Experiences Paul W. Homer FRoM All oF ouR ExpERiEnCES, including both suc ...

  4. POJ1390 Blocks 【动态规划】

    Blocks Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4173   Accepted: 1661 Descriptio ...

  5. hadoop 计数器

    一.hadoop有非常多自带的计数器,相信看过执行log的都会看到各种数据 二.用户自己定义计数器 在开发中常常须要记录错误的数据条数,就能够用计数器来解决. 1.定义:用一个枚举来定义一组计数器,枚 ...

  6. jQuery插件开发的两种方法

    1 类级别 类级别你可以理解为拓展jquery类,最明显的例子是$.ajax(...),相当于静态方法. 开发扩展其方法时使用$.extend方法,即jQuery.extend(object); $. ...

  7. .NET Core开发:项目实践

    初始化项目 本来想详细讲一讲dotnet core的,但我对于dotnet core的研究还不到一星期,半吊子,脑子又笨,就不写那些理论出来误人子弟了,还是直接来一篇实践给大家做个参考.废话不多说,直 ...

  8. ROS-多机通信

    前言:一定要在同一路由的局域网下进行,就是两台电脑的ip要像这样:192.168.191.4和192.168.191.8,只有最后一位不同,这样就能ping通了,否则ping不同. 一.查看ip和主机 ...

  9. codeforces 277 A Learning Languages 【DFS 】

    n个人,每个人会一些语言,两个人只要有会一门相同的语言就可以交流,问为了让这n个人都交流,至少还得学多少门语言 先根据n个人之间他们会的语言,建边 再dfs找出有多少个联通块ans,再加ans-1条边 ...

  10. POJ 1995 Raising Modulo Numbers 【快速幂取模】

    题目链接:http://poj.org/problem?id=1995 解题思路:用整数快速幂算法算出每一个 Ai^Bi,然后依次相加取模即可. #include<stdio.h> lon ...