【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

Sample Output

8
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 }

 

posted @ 2017-06-18 15:31  cot  阅读(187)  评论(0编辑  收藏  举报