【BZOJ3626】 [LNOI2014]LCA
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
0
0
1
1
1 4 3
1 4 2
Sample Output
8
5
5
HINT
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
Solution
学长口中的套路题,然后就第一次学这个“套路”。。。
形式化地,假如我们要求一个点到一个点集里所有点的LCA的深度之和的话,我们可以把这个点集到根的路径上的权值全部加1,然后再查询这个点到根的权值之和就行了。
因为这题具有可减性,所以可以转换成两个前缀相减的询问。
路径上权值+1和查询链上权值之和可以用树链剖分线段树来解决。
Code
1 #include <cstdio> 2 #include <algorithm> 3 4 #define maxn 50010 5 #define R register 6 #define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0) 7 const int mod = 201314; 8 struct Edge { 9 Edge *next; 10 int to; 11 } *last[maxn], e[maxn], *ecnt = e; 12 inline void link(R int a, R int b) 13 { 14 *++ecnt = (Edge) {last[a], b}; last[a] = ecnt; 15 } 16 int fa[maxn], son[maxn], size[maxn], dep[maxn], top[maxn], dfn[maxn], pos[maxn], timer, rig[maxn]; 17 int tot, tr[maxn << 2], tag[maxn << 2], ls[maxn << 2], rs[maxn << 2], rt[maxn]; 18 struct Query { 19 int x, u, id, type; 20 inline bool operator < (const Query &that) const {return x < that.x;} 21 } q[maxn << 2]; 22 int qcnt, ans[maxn], ql, qr; 23 void dfs1(R int x) 24 { 25 dep[x] = dep[fa[x]] + 1; size[x] = 1; 26 for (R Edge *iter = last[x]; iter; iter = iter -> next) 27 { 28 dfs1(iter -> to); 29 size[x] += size[iter -> to]; 30 size[son[x]] < size[iter -> to] ? son[x] = iter -> to : 0; 31 } 32 } 33 void dfs2(R int x) 34 { 35 top[x] = son[fa[x]] == x ? top[fa[x]] : x; dfn[x] = ++timer; pos[timer] = x; 36 cmax(rig[top[x]], dfn[x]); 37 if (son[x]) dfs2(son[x]); 38 for (R Edge *iter = last[x]; iter; iter = iter -> next) if (iter -> to != son[x]) dfs2(iter -> to); 39 } 40 int build(R int l, R int r) 41 { 42 R int now = ++tot; 43 if (l == r) return now; 44 R int mid = l + r >> 1; 45 ls[now] = build(l, mid); 46 rs[now] = build(mid + 1, r); 47 return now; 48 } 49 inline void pushdown(R int o, R int l, R int r, R int mid) 50 { 51 if (tag[o]) 52 { 53 tag[ls[o]] += tag[o]; 54 tag[rs[o]] += tag[o]; 55 tr[ls[o]] += tag[o] * (mid - l + 1); 56 tr[rs[o]] += tag[o] * (r - mid); 57 tag[o] = 0; 58 } 59 } 60 inline void update(R int o) 61 { 62 tr[o] = tr[ls[o]] + tr[rs[o]]; 63 } 64 void modify(R int o, R int l, R int r) 65 { 66 if (ql <= l && r <= qr) 67 { 68 ++tag[o]; 69 tr[o] += r - l + 1; 70 return ; 71 } 72 R int mid = l + r >> 1; 73 pushdown(o, l, r, mid); 74 if (ql <= mid) modify(ls[o], l, mid); 75 if (mid < qr) modify(rs[o], mid + 1, r); 76 update(o); 77 } 78 int query(R int o, R int l, R int r) 79 { 80 if (ql <= l && r <= qr) 81 return tr[o]; 82 R int mid = l + r >> 1, ret = 0; 83 pushdown(o, l, r, mid); 84 if (ql <= mid) (ret += query(ls[o], l, mid)) %= mod; 85 if (mid < qr) (ret += query(rs[o], mid + 1, r)) %= mod; 86 update(o); 87 return ret; 88 } 89 inline void tr_add(R int x) 90 { 91 while (x) 92 { 93 ql = dfn[top[x]]; 94 qr = dfn[x]; 95 modify(rt[top[x]], dfn[top[x]], rig[top[x]]); 96 x = fa[top[x]]; 97 } 98 } 99 inline int tr_query(R int x) 100 { 101 R int ret = 0; 102 while (x) 103 { 104 ql = dfn[top[x]]; 105 qr = dfn[x]; 106 (ret += query(rt[top[x]], dfn[top[x]], rig[top[x]])) %= mod; 107 x = fa[top[x]]; 108 } 109 return ret; 110 } 111 int main() 112 { 113 R int n, qq; scanf("%d%d", &n, &qq); 114 for (R int i = 2; i <= n; ++i) 115 { 116 R int f; scanf("%d", &f); ++f; 117 link(fa[i] = f, i); 118 } 119 for (R int i = 1; i <= qq; ++i) 120 { 121 R int l, r, u; scanf("%d%d%d", &l, &r, &u); 122 ++r; ++u; 123 if (l > 0) q[++qcnt] = (Query) {l, u, i, -1}; 124 q[++qcnt] = (Query) {r, u, i, 1}; 125 } 126 std::sort(q + 1, q + qcnt + 1); 127 dfs1(1); dfs2(1); 128 for (R int i = 1; i <= n; ++i) 129 if (top[i] == i) 130 rt[i] = build(dfn[i], rig[i]); 131 132 for (R int i = 1, j = 1; i <= n; ++i) 133 { 134 tr_add(i); 135 while (j <= qcnt && q[j].x == i) 136 { 137 ans[q[j].id] += tr_query(q[j].u) * q[j].type; 138 ++j; 139 } 140 } 141 for (R int i = 1; i <= qq; ++i) printf("%d\n", (ans[i] + mod) % mod); 142 return 0; 143 }