我是靠谱客的博主 结实老鼠,这篇文章主要介绍【Bzoj3626】LCA,现在分享给大家,希望可以做个参考。

题意

给出一个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的最近公共祖先的深度之和)


解析

  首先发现一个性质,加上depth[LCA(l,r)]可以等价于将根到l加上1,之后查询根到r。扩展到区间的话,设要求结点为z,区间[l,r]。也就是从1加到r后对z的查询值减去1加到l-1对z的查询值。这样的话可以把询问先离线排序,之后树链剖分维护,在标记一下就可以了。


复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
#include <cstdio> #include <algorithm> #define Rep( i , B , E ) for(int i=B;i<=E;i++) #define For( i , B , E ) for(int i=B;i;i=E) using namespace std; const int maxx = 100000 + 25; const int mod = 201314; int head[maxx],to[maxx<<1],nxt[maxx<<1]; int top[maxx],ftr[maxx],son[maxx],rnk[maxx],size[maxx],dpt[maxx]; int T[maxx<<2],Add[maxx<<2],Ans[maxx]; int n,m,x,y,z,num,cnt,tot,pos = 1; namespace Y{ void Ins(int x,int y) {to[++num]=y;nxt[num]=head[x];head[x]=num;} void Dfs1(int x){ size[x] = 1; For( i , head[x] , nxt[i] ){ int now = to[i];if(now == ftr[x]) continue; dpt[now] = dpt[x] + 1;ftr[now] = x; Dfs1(now);size[x] += size[now]; if(size[now] > size[son[x]]) son[x] = now; } } void Dfs2(int x,int brn){ rnk[x] = ++cnt;top[x] = brn; if(son[x]) Dfs2(son[x],brn); For( i , head[x] , nxt[i] ) if(to[i] != ftr[x] && to[i] != son[x]) Dfs2(to[i],to[i]); } void pushdown(int i,int l,int r){ int mid = (l+r) >> 1;int k = Add[i]; T[i<<1] += (mid-l+1)*k;T[i<<1|1] += (r-mid)*k; Add[i<<1] += k;Add[i<<1|1] += k;Add[i] = 0; } void modify(int i,int x,int y,int l,int r,int k){ if(x <= l && r <= y) {T[i] += (r-l+1)*k;Add[i] += k;return;} if(Add[i]) pushdown(i,l,r);int mid = (l+r) >> 1; if(x <= mid) modify(i<<1,x,y,l,mid,k); if(y > mid) modify(i<<1|1,x,y,mid+1,r,k); T[i] = (T[i<<1] + T[i<<1|1]) % mod; } int Query(int i,int x,int y,int l,int r){ if(x <= l && r <= y) return T[i] % mod;int ans = 0; int mid = (l+r) >> 1;if(Add[i]) pushdown(i,l,r); if(x <= mid) ans = (ans + Query(i<<1,x,y,l,mid)) % mod; if(y > mid) ans = (ans + Query(i<<1|1,x,y,mid+1,r)) % mod; return ans; } void update(int x,int y,int k){ while(top[x] != top[y]){ if(dpt[top[x]] > dpt[top[y]]) x^=y^=x^=y; modify(1,rnk[top[y]],rnk[y],1,n,k); y = ftr[top[y]]; } if(rnk[x] > rnk[y]) x^=y^=x^=y; modify(1,rnk[x],rnk[y],1,n,k); } int Get(int x,int y){ int ans = 0; while(top[x] != top[y]){ if(dpt[top[x]] > dpt[top[y]]) x^=y^=x^=y; ans = (ans + Query(1,rnk[top[y]],rnk[y],1,n)) % mod; y = ftr[top[y]]; } if(rnk[x] > rnk[y]) x^=y^=x^=y; ans = (ans + Query(1,rnk[x],rnk[y],1,n)) % mod; return ans; } } namespace Question{ struct Que{ int l; int f; int d; int id; }Q[maxx]; bool cmp(Que a,Que b){ if(a.l != b.l) return a.l < b.l; return a.id < b.id; } } using namespace Y; using namespace Question; int main(){ scanf("%d%d",&n,&m); Rep( i , 2 , n ) scanf("%d",&x),Ins(i,x+1),Ins(x+1,i); Dfs1(1);Dfs2(1,1); Rep( i , 1 , m ){ scanf("%d%d%d",&x,&y,&z);x++;y++;z++; Q[++tot].id = i;Q[tot].l = x-1;Q[tot].d = z;Q[tot].f = 1; Q[++tot].id = i;Q[tot].l = y; Q[tot].d = z;Q[tot].f = -1; } sort(Q+1,Q+tot+1,cmp); Rep( i , 1 , tot ){ while(pos <= Q[i].l){ update(1,pos,1); pos ++; } if(Q[i].f == 1) Ans[Q[i].id] -= Get(1,Q[i].d); if(Q[i].f == -1) Ans[Q[i].id] += Get(1,Q[i].d); } Rep( i , 1 , m ) printf("%dn",(Ans[i]%mod+mod)%mod); return 0; }

最后

以上就是结实老鼠最近收集整理的关于【Bzoj3626】LCA的全部内容,更多相关【Bzoj3626】LCA内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(75)

评论列表共有 0 条评论

立即
投稿
返回
顶部