3626: [LNOI2014]LCA

Time Limit: 10 Sec   Memory Limit: 128 MB

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。

很经典的树剖题,学会了一种新的方法。

预备一下做法:

对于要求的i, z的LCA的祖先深度,我们可以这样做,首先将从i到根的每个节点都+1,然后统计从z到根的和,和即为深度,如图:

离线询问,将一个询问区间拆成[1, l-1]和[1, r],那么[l, r]的和就变成了sum[1, r] - sum[1, l - 1]

将所有点按照轻重链先后dfs序重编号,那么重链上的点编号一定是连续的,一个点也是重链。

用重新编的号作为线段树的下标。

从1~N每个点暴力向根节点+1,然后每次就统计从z到根的和,就是当时的[1, i]的sum。

加的时候就是按着轻重链剖分的方法,一直tp到根,每一段重链可以直接按照新编号的下标直接在线段树上更新区间。

每次查询也是按着轻重链剖分的方法,一直tp到根,每次询问一段重链的和。

时间复杂度为Nlog^2 N

Code:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;const int Max = 50000;
const int MOD = 201314;struct node{int pos, t, id, tg;bool operator < (const node X)const{return pos < X.pos;}
}Ask[(Max << 1) + 5];
struct TREE{int l, r, sum, ad, num;
}Tr[(Max << 2) + 5];int N, Q, ecnt, POS;
int fir[Max + 5], nxt[Max + 5], V[Max + 5], An[(Max << 1) + 5];
int fa[Max + 5], sz[Max + 5], son[Max + 5], tp[Max + 5], Dep[Max + 5];
int ID[Max + 5], P[Max + 5];void getint(int & num){char c; int flg = 1;    num = 0;while((c = getchar()) < '0' || c > '9') if(c == '-')    flg = -1;while(c >= '0' && c <= '9'){    num = num * 10 + c - 48;    c = getchar(); }num *= flg;
}void addedge(int a, int b){V[++ ecnt] = b, nxt[ecnt] = fir[a], fir[a] = ecnt;
}void Dfs1(int u, int ff){Dep[u] = Dep[ff] + 1;sz[u] = 1;for(int i = fir[u]; i; i = nxt[i]){Dfs1(V[i], u), sz[u] += sz[V[i]];if(sz[V[i]] > sz[son[u]])   son[u] = V[i];}
}void Dfs2(int u){ID[u] = ++ POS;P[POS] = u;if(son[u]){tp[son[u]] = tp[u];Dfs2(son[u]);}for(int i = fir[u]; i; i = nxt[i])  if(V[i] != fa[u] && V[i] != son[u])tp[V[i]] = V[i],Dfs2(V[i]);
}void Build(int i, int l, int r){Tr[i].l = l, Tr[i].r = r, Tr[i].sum = Tr[i].ad = 0;if(l == r){Tr[i].num = P[l], Tr[i].sum = 0;return ;}int mid = (l + r) >> 1;Build(i << 1, l, mid);Build(i << 1 | 1, mid + 1, r);Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;
}void pushdown(int i){int lc = i << 1, rc = i << 1 | 1;Tr[lc].ad = (Tr[lc].ad + Tr[i].ad) % MOD;Tr[rc].ad = (Tr[rc].ad + Tr[i].ad) % MOD;Tr[lc].sum = (Tr[lc].sum + 1ll*Tr[i].ad * (Tr[lc].r - Tr[lc].l + 1) % MOD) % MOD;Tr[rc].sum = (Tr[rc].sum + 1ll*Tr[i].ad * (Tr[rc].r - Tr[rc].l + 1) % MOD) % MOD;Tr[i].ad = 0;
}void Add(int i, int L, int R){if(L <= Tr[i].l && R >= Tr[i].r){Tr[i].ad = (Tr[i].ad + 1) % MOD;Tr[i].sum = (Tr[i].sum + Tr[i].r - Tr[i].l + 1) % MOD;return ;}int mid = (Tr[i].l + Tr[i].r) >> 1;if(Tr[i].ad)   pushdown(i);if(L <= mid)    Add(i << 1, L, R);if(R > mid) Add(i << 1 | 1, L, R);Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;
}int Query(int i, int L, int R){if(L <= Tr[i].l && R >= Tr[i].r)    return Tr[i].sum;if(Tr[i].ad)    pushdown(i);int mid = (Tr[i].l + Tr[i].r) >> 1, rt = 0;if(L <= mid)    rt = (rt + Query(i << 1, L, R)) % MOD;if(R > mid)     rt = (rt + Query(i << 1 | 1, L, R)) % MOD;Tr[i].sum = (Tr[i << 1].sum + Tr[i << 1 | 1].sum) % MOD;return rt;
}void Update(int u){while(u){Add(1, ID[tp[u]], ID[u]);u = fa[tp[u]];}
}int Cal(int u){int rt = 0;while(u){rt = (rt + Query(1, ID[tp[u]], ID[u])) % MOD;u = fa[tp[u]];}return rt;
}int main(){getint(N), getint(Q);for(int i = 2; i <= N; ++ i)getint(fa[i]), ++ fa[i], addedge(fa[i], i);Dfs1(1, 0);tp[1] = 1;Dfs2(1);Build(1, 1, N);int l, r, T = 0;int R = 0;for(int i = 1; i <= Q; ++ i){getint(l), getint(r), getint(Ask[++ T].t);++ l, ++ r, ++ Ask[T].t;Ask[T].pos = l - 1, Ask[T].id = i, Ask[T].tg = -1, ++ T;Ask[T].t = Ask[T - 1].t, Ask[T].pos = r, Ask[T].id = i, Ask[T].tg = 1;R = max(R, r);}sort(Ask + 1, Ask + 1 + T);int p = 1;for(int i = 1; i <= T; ){while(p <= Ask[i].pos){Update(p), ++ p;}int j;for(j = i; j <= T && Ask[j].pos == Ask[i].pos; ++ j){int tmp = Cal(Ask[j].t);An[Ask[j].id] += Ask[j].tg * tmp ;}i = j;}for(int i = 1; i <= Q; ++ i)    printf("%d\n", (An[i] + MOD) % MOD);return 0;
}

/*

5 2
0
0
1
1
1 4 3
1 4 2

7 5
0 0 1 1 2 2
0 6 0
0 6 1
5 6 2
5 6 1
0 4 1
7
10
4
2
8

*/

#HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)相关推荐

  1. BZOJ3531-[Sdoi2014]旅行(树剖+线段树动态开点)

    传送门 完了今天才知道原来线段树的动态开点和主席树是不一样的啊 我们先考虑没有宗教信仰的限制,那么就是一个很明显的树剖+线段树,路径查询最大值以及路径和 然后有了宗教信仰的限制该怎么做呢? 先考虑暴力 ...

  2. BZOJ 4817: [Sdoi2017]树点涂色(LCT+树剖+线段树)

    题目描述 Bob有一棵 nn 个点的有根树,其中1号点是根节点.Bob在每个点上涂了颜色,并且每个点上的颜色不同. 定义一条路径的权值是:这条路径上的点(包括起点和终点)共有多少种不同的颜色. Bob ...

  3. 树剖+线段树||树链剖分||BZOJ1984||Luogu4315||月下“毛景树”

    题面:月下"毛景树" 题解:是道很裸的树剖,但处理的细节有点多(其实是自己线段树没学好).用一个Dfs把边权下移到点权,用E数组记录哪些边被用到了:前三个更新的操作都可以合并起来, ...

  4. BZOJ4034 树上操作(树剖 线段树大模板)

    BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #inc ...

  5. 2019ICPC西安邀请赛 E. Tree(树剖 + 线段树)

    Tree 给定一棵树,节点有点权,然后有三种操作: 一.修改1−>s1->s1−>s的路径上的点权与ttt进行按位或. 二.修改1−>s1->s1−>s的路径上的点 ...

  6. P3292 [SCOI2016]幸运数字(树剖 + 线段树维护线性基)

    P3292 [SCOI2016]幸运数字 思路 如果这题是求x,yx, yx,y之间的距离显然我们可以通过树剖加线段树来写, 但是这里变成了求任意个数的异或最大值.如果给定区间我们显然可以通过线性基来 ...

  7. ural 1553 树剖+线段树

    //链式前向星版 #include<bits/stdc++.h> using namespace std; const int maxn=100010; //建图 int to[maxn* ...

  8. 2021 Jiangsu Collegiate Programming Contest F. Jumping Monkey II 树剖+线段树

    F. Jumping Monkey II 题意: 给你 n = 2 e 5 n=2e5 n=2e5的一棵树,每个点有点权 a [ i ] < = 1 e 9 a[i]<=1e9 a[i]& ...

  9. 洛谷2543AHOI2005]航线规划 (树剖+线段树+割边思路)

    这个题的思路还是比较巧妙的. 首先,我们发现操作只有删除和询问两种,而删除并不好维护连通性和割边之类的信息. 所以我们不妨像WC2006水管局长那样,将询问离线,然后把操作转化成加边和询问. 然后,我 ...

最新文章

  1. 【C++】 15_类于封装的概念
  2. Xamarin图表开发基础教程(3)OxyPlot框架
  3. WF4 持久化 第四篇
  4. BGP、MPLS是怎么组合到一起的?
  5. 还在为系统迁移烦恼?掌握这些“基本法”解锁更多可能
  6. 开发者基础知识游戏,共10关,欢迎挑战
  7. java 基本语法与流程控制_Java基础语法之控制流程
  8. 【OS学习笔记】二十八 保护模式八:任务切换对应的汇编代码之内核代码
  9. 【HDU - 2717】【POJ - 3278】Catch That Cow (经典bfs,类似dp)
  10. EMC VMAX的磁盘构成,fast policy(重要)
  11. 网页制作的基本语言html,网页制作基础语言HTML.ppt
  12. 【转】怎样成为优秀的软件模型设计者(文末提供下载)
  13. android wifi在待机状态下可用,Android APP休眠状态下无法联网和播放音频解决方案...
  14. C++——override
  15. 从72万现金到骨灰盒,还有什么是不能被忘在网约车上的?
  16. true是不是python保留字_Python基本语法--关键字和保留字篇
  17. VB模拟键盘输入的N种方法
  18. 怎么实现角色权限的分配_在 Go 语言中使用 casbin 实现基于角色的 HTTP 权限控制...
  19. ele input事件 输入后0.5秒触发
  20. 调整计算机繁体,在线繁体转换

热门文章

  1. C++初级程序员笔试题总结
  2. 苹果全球开发者大会(WWDC)视频观略
  3. RDB内存快照:Redis如何实现快速恢复数据
  4. 获取指定日期的下个月
  5. Charles使用方法(Map Local)
  6. 2021年安全员-B证考试及安全员-B证最新解析
  7. 希腊字母拼写与读音中英对照一览表 暨 希腊键盘键位对照表
  8. 爱看广场舞的老爷爷的脚本日记
  9. 基于目的转发和通用转发区别
  10. PK656个对手!深兰科技在全球顶级AI赛事kaggle竞赛中再次夺冠