zoukankan      html  css  js  c++  java
  • 【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
    ", (ans[i] + mod) % mod);
    142     return 0;
    143 }
  • 相关阅读:
    读取STL模型 并用opengl显示
    金币阵列问题
    字典序问题的解决方案
    opengl中的旋转与平移
    copy文件夹,通过C++读取系统、用户名以及计算机名的方法
    poj3032
    菲涅尔反射(Fresnel Reflection)
    几个稍大场景的渲染测试
    Ward BRDF实现心得
    离线渲染中的不规则光源(Meshlight)
  • 原文地址:https://www.cnblogs.com/cocottt/p/7044414.html
Copyright © 2011-2022 走看看