#HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)
来源:互联网 发布:java记事本代码讲解 编辑:程序博客网 时间:2024/06/07 02:11
3626: [LNOI2014]LCA
Time Limit: 10 Sec Memory Limit: 128 MBDescription
给出一个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
0
0
1
1
1 4 3
1 4 2
Sample Output
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(经典模型:树剖+线段树维护和)
- bzoj3626: [LNOI2014]LCA (树链剖分+离线线段树)
- BZOJ[3626][LNOI2014]LCA 树链剖分+线段树
- 3626: [LNOI2014]LCA|动态树
- bzoj 3626: [LNOI2014]LCA
- 【BZOJ3626】 [LNOI2014]LCA
- 【BZOJ 3626】 [LNOI2014]LCA
- [bzoj 3626] LNOI2014 LCA
- BZOJ3626: [LNOI2014]LCA
- bzoj3626【LNOI2014】LCA
- [BZOJ3626] [LNOI2014]LCA
- 3626: [LNOI2014]LCA LCT
- BZOJ3626: [LNOI2014]LCA
- [bzoj3626][LNOI2014]LCA
- [LNOI2014][BZOJ3626]LCA
- BZOJ3626 [LNOI2014]LCA
- BZOJ 3626 [LNOI2014]LCA
- 3626: [LNOI2014]LCA
- Java (堆和栈),内存地址,==,equals,hashCode
- 数据科学与算法概述
- linux中Framebuffer的原理及实现机制
- redis主从复制以及哨兵机制
- git 基本操作
- #HYSBZ3626[LNOI2014]#LCA(经典模型:树剖+线段树维护和)
- kubernetes安装教程,离线安装,内网安装,1.8版本,包含安装包
- 约瑟夫环问题用Python的解法
- Python实现 Pat1019 数字黑洞
- js事件机制
- Vue2中的键盘事件
- Java8函数式编程之七:Stream(流)的各种操作
- LeetCode——Climbing Stairs
- 初识多线程