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。

题解

[HNOI 2015]开店的简化版。

 //It is made by Awson on 2018.1.8
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define RE register
#define lowbit(x) ((x)&(-(x)))
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
#define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
using namespace std;
const int N = ;
const int MOD = ;
const int INF = ~0u>>; int n, q, f, u, v, c, fa[N+], dep[N+], top[N+], cnt, size[N+], son[N+], pos[N+];
struct tt {
int to, next;
}edge[N+];
int path[N+], tot;
void add(int u, int v) {
edge[++tot].to = v;
edge[tot].next = path[u];
path[u] = tot;
}
struct Segment_tree {
int root[N+], sum[N*+], lazy[N*+], ch[N*][], pos;
int newnode(int r) {
int o = ++pos; sum[o] = sum[r], lazy[o] = lazy[r], ch[o][] = ch[r][], ch[o][] = ch[r][];
return o;
}
void update(int &o, int l, int r, int a, int b, int last) {
if (o <= last) o = newnode(o);
if (a <= l && r <= b) {
sum[o] += r-l+, sum[o] %= MOD, lazy[o]++; return;
}
int mid = (l+r)>>;
if (mid >= a) update(ch[o][], l, mid, a, b, last);
if (mid < b) update(ch[o][], mid+, r, a, b, last);
sum[o] = (sum[ch[o][]]+sum[ch[o][]]+(LL)lazy[o]*(r-l+)%MOD)%MOD;
}
int query(int o, int l, int r, int a, int b) {
if (!o) return ;
if (a <= l && r <= b) return sum[o];
int mid = (l+r)>>, c1 = , c2 = ;
if (mid >= a) c1 = query(ch[o][], l, mid, a, b);
if (mid < b) c2 = query(ch[o][], mid+, r, a, b);
return (c1+c2+(LL)lazy[o]*(Min(r, b)-Max(l, a)+)%MOD)%MOD;
}
}T;
void dfs1(int o, int father, int depth) {
fa[o] = father, dep[o] = depth+, size[o] = ;
for (int i = path[o]; i; i = edge[i].next) {
dfs1(edge[i].to, o, depth+);
size[o] += size[edge[i].to];
if (size[edge[i].to] > size[son[o]]) son[o] = edge[i].to;
}
}
void dfs2(int o, int tp) {
top[o] = tp, pos[o] = ++cnt;
if (son[o]) dfs2(son[o], tp);
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != son[o]) dfs2(edge[i].to, edge[i].to);
}
void lca_update(int id, int o, int last) {while (top[o]) T.update(T.root[id], , n, pos[top[o]], pos[o], last), o = fa[top[o]]; }
int lca_query(int id, int o) {
int ans = ;
while (top[o]) ans += T.query(T.root[id], , n, pos[top[o]], pos[o]), ans %= MOD, o = fa[top[o]];
return ans;
}
void work() {
scanf("%d%d", &n, &q);
for (int i = ; i <= n; i++) scanf("%d", &f), add(f+, i);
dfs1(, , ), dfs2(, );
for (int i = ; i <= n; i++) {
T.root[i] = T.root[i-]; lca_update(i, i, T.pos);
}
while (q--) {
scanf("%d%d%d", &u, &v, &c);
printf("%d\n", (lca_query(v+, c+)-lca_query(u, c+)+MOD)%MOD);
}
}
int main() {
work();
return ;
}

[LNOI 2014]LCA的更多相关文章

  1. 解题:LNOI 2014 LCA

    题面 这题有点意思 转化问题,我们把询问区间的点到根链加,再查询询问点到根的权值和就是每个询问的答案. 然后如果你数据结构没学傻只需要差分一下就可以扫一遍出解了 #include<cstdio& ...

  2. 【LNOI 2014】 LCA

    [题目链接] 点击打开链接 [算法] 考虑求lca(x,y)的深度 我们可以将从根到x路径上的点都打上标记,然后,询问y到根上路径的权值和 那么,求sigma(depth(lca(i,z)))(l & ...

  3. bzoj 4012: [HNOI2015]开店

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  4. [GXOI/GZOI2019]旧词

    很像LNOI 2014 LCA那道题. 同样的套路,离线以后直接扫描线. k=1的话就是原题. 考虑一般情况. 原本的做法是对x到根的这条链做一下区间+1操作,目的是为了是的在深度为i的位置得到的贡献 ...

  5. bzoj 4012: [HNOI2015]开店 主席树

    Description 风见幽香有一个好朋友叫八云紫,她们经常一起看星星看月亮从诗词歌赋谈到 人生哲学.最近她们灵机一动,打算在幻想乡开一家小店来做生意赚点钱.这样的 想法当然非常好啦,但是她们也发现 ...

  6. BZOJ 5507: [gzoi2019]旧词 LCT

    和之前那个 [LNOI]LCA 几乎是同一道题,就是用动态树来维护查分就行. code: #include <bits/stdc++.h> using namespace std; #de ...

  7. [HNOI2015]开店 简要题解

    主席树. 推下式子,发现点的深度和好算,lca深度和不好算. lca深度之和有个套路:先给a到根路径+1,再算b到根的和. 如果可以离线,即LNOI的LCA.本题强制在线,可持久化. 由于区间修改,使 ...

  8. HDU_4912 Path on the tree 2014多校5 贪心+LCA

    当时刚学LCA-tarjan不久,就比赛有这个题,但没想到还是没做出来..一开始以为是DP来着,没想到是贪心,想想也对,从树的最下层开始,每次遇到询问的点,就找到他们的LCA(路径里面必经LCA),然 ...

  9. LOJ #2876. 「JOISC 2014 Day2」水壶 BFS+最小生成树+倍增LCA

    非常好的一道图论问题. 显然,我们要求城市间的最小生成树,然后查询路径最大值. 然后我们有一个非常神的处理方法:进行多源 BFS,处理出每一个城市的管辖范围. 显然,如果两个城市的管辖范围没有交集的话 ...

随机推荐

  1. Java 自定义实现链表

    自定义实现链表很简单,只需要明白链表是什么样子的数据结构. 下图表示一种单向列表.其中指针first指向队头,last指向队尾,curr指向当前读的数据. 下面是我的实现代码,很简单,明白上述结构后, ...

  2. Java之排序

    1.插入排序 假设第一个数已经是排好序的,把第二个根据大小关系插到第一个前面或维持不动,把第三个根据前面两个的大小关系插到对应位置,依次往后. public class InsertSort { pu ...

  3. vim的配置

    修改根目录下.vimrc文件: 1.设定解码,支持中文 set fileencodings=utf-8,ucs-born,gb18030,gbk,gb2312,cp936 set termencodi ...

  4. 网络1711班 C语言第八次作业批改总结

    网络1711班 C语言第七次作业批改总结 最近在忙一些琐事,没能及时批改大家的作业,连续两次作业总结也没有很用心写,在这要给大家say sorry. 1.本次作业评分细则 1.1 基本要求(1分) 按 ...

  5. Java的HelloWorld程序

    Java的HelloWorld程序 1.新建文本文档,编写HelloWorld程序,最后保存时记得保存成.java格式 2.在D盘新建一个HelloJava文件夹用于保存java程序 3.使用WIN+ ...

  6. 网上找的hadoop面试题目及答案

    1.Hadoop集群可以运行的3个模式? 单机(本地)模式 伪分布式模式全分布式模式2. 单机(本地)模式中的注意点? 在单机模式(standalone)中不会存在守护进程,所有东西都运行在一个JVM ...

  7. java克隆之深拷贝与浅拷贝

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java深拷贝与浅拷贝实际项目中用的不多,但是对于理解Java中值传递,引用传递十分重要,同时个人认为对于理解内存模型也有帮助,况且面试中也是经常问 ...

  8. react中的DOM操作

    前面的话 某些情况下需要在典型数据流外强制修改子代.要修改的子代可以是 React 组件实例,也可以是 DOM 元素.这时就要用到refs来操作DOM 使用场景 下面是几个适合使用 refs 的情况 ...

  9. JAVA_SE基础——16.方法

    接触过C语言的同学,这小章节很容易接受.Java中的方法是类似与C语言中的函数  功能和调用方法都类似  只不过叫法不一样  因为java是面向对象  c是面向过程    仅仅是叫法不同.. . 看到 ...

  10. emqtt 试用(七)追踪

    追踪 EMQ 消息服务器支持追踪来自某个客户端(Client)的全部报文,或者发布到某个主题(Topic)的全部消息. 追踪客户端(Client): ./bin/emqttd_ctl trace cl ...