zoukankan      html  css  js  c++  java
  • [LNOI2014]LCA

    嘟嘟嘟

    不得不说,这道题出的真是太好了!

    正解直接说出来太突兀了,还是先从暴力开始。

    首先,如果看到题目就像怎么求LCA,那就凉凉(也不想想,省选题会在题目中告诉你做法吗?!)。

    除非有一种方法一次把LCA都求出来,或者是把这个求多个deep的和转化一下。

    反正第一种方法我是不会。

    至于求多个deep的和,我们从整体上考虑:每一个LCA对答案的贡献多少。我们发现,z的LCA一定在z到根节点的路径上,而且deep[u]就是u到根节点经过的节点数目。所以我们可以把每一个LCA到根节点的的路径中的所有点权值都加1,然后从z跑一边加上路径上的点的贡献即可。

    所以对于一组查询[L, R] 和z,可以枚举 i (i :L ~ R) 。然后给 i 到根的路径每一个点都加1,最后z在跑一边统计即可。又因为是树上路径的操作,可以用树剖维护。复杂度O(q * n * (logn)2)。

    考虑怎么优化:对于查询区间[L, R],用前缀和的思想[L, R] = [1, R] - [1, L - 1]。可以先求出[1, L - 1]的答案,然后求出[1, R]的答案,最后相减即可。于是我们把所有答案离线下来,开一个标记数组sec,给sec[L - 1]和sec[R]标记。然后从1到n扫,每一次都把 i 到根的路径权值加1,如果sec[i]有标记,就查询一下,累加到这个询问的答案中。

    然后注意一下细节:

    1.标记数组要开一个vector,因为区间端点可能重复。

    2.标记有这么几个参数:id : 询问编号, flg : -1表示做端点,要减去;1表示区间右端点,要加上, z : 就是题中的z。

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cmath>
      4 #include<algorithm>
      5 #include<cstring>
      6 #include<cstdlib>
      7 #include<cctype>
      8 #include<vector>
      9 #include<stack>
     10 #include<queue>
     11 using namespace std;
     12 #define enter puts("") 
     13 #define space putchar(' ')
     14 #define Mem(a, x) memset(a, x, sizeof(a))
     15 #define rg register
     16 typedef long long ll;
     17 typedef double db;
     18 const int INF = 0x3f3f3f3f;
     19 const db eps = 1e-8;
     20 const int maxn = 5e4 + 5;
     21 const int mod = 201314;
     22 inline ll read()
     23 {
     24     ll ans = 0;
     25     char ch = getchar(), last = ' ';
     26     while(!isdigit(ch)) {last = ch; ch = getchar();}
     27     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
     28     if(last == '-') ans = -ans;
     29     return ans;
     30 }
     31 inline void write(ll x)
     32 {
     33     if(x < 0) x = -x, putchar('-');
     34     if(x >= 10) write(x / 10);
     35     putchar(x % 10 + '0');
     36 }
     37 
     38 int n, q;
     39 vector<int> v[maxn];
     40 
     41 int fa[maxn], dep[maxn], siz[maxn], son[maxn];
     42 void dfs1(int now)
     43 {
     44     siz[now] = 1;
     45     for(int i = 0; i < (int)v[now].size(); ++i)
     46     {
     47         dep[v[now][i]] = dep[now] + 1;
     48         fa[v[now][i]] = now;
     49         dfs1(v[now][i]);
     50         siz[now] += siz[v[now][i]];
     51         if(!son[now] || siz[son[now]] < siz[v[now][i]]) son[now] = v[now][i];
     52     }
     53 }
     54 int dfsx[maxn], pos[maxn], top[maxn], cnt = 0;
     55 void dfs2(int now)
     56 {
     57     dfsx[now] = ++cnt; pos[cnt] = now;
     58     if(son[now])
     59     {
     60         top[son[now]] = top[now];
     61         dfs2(son[now]);
     62     }
     63     for(int i = 0; i < (int)v[now].size(); ++i)
     64     {
     65         if(v[now][i] != son[now])
     66         {
     67             top[v[now][i]] = v[now][i];
     68             dfs2(v[now][i]);
     69         }
     70     }
     71 }
     72 
     73 void Mod(int& x)
     74 {
     75     if(x > mod) x -= mod;
     76 }
     77 
     78 int l[maxn << 2], r[maxn << 2], sum[maxn << 2], lzy[maxn << 2];
     79 void build(int L, int R, int now)
     80 {
     81     l[now] = L; r[now] = R;
     82     if(L == R) return;
     83     int mid = (L + R) >> 1;
     84     build(L, mid, now << 1);
     85     build(mid + 1, R, now << 1 | 1);
     86 }
     87 void pushdown(int now)
     88 {
     89     if(lzy[now])
     90     {
     91         sum[now << 1] += lzy[now] * (r[now << 1] - l[now << 1] + 1); Mod(sum[now << 1]);
     92         sum[now << 1 | 1] += lzy[now] * (r[now << 1 | 1] - l[now << 1 | 1] + 1); Mod(sum[now << 1 | 1]);
     93         lzy[now << 1] += lzy[now]; Mod(lzy[now << 1]);
     94         lzy[now << 1 | 1] += lzy[now]; Mod(lzy[now << 1 | 1]);
     95         lzy[now] = 0;
     96     }
     97 }
     98 void update(int L, int R, int now)
     99 {
    100     if(L == l[now] && R == r[now]) 
    101     {
    102         sum[now] += R - L + 1; lzy[now]++;
    103         Mod(sum[now]); Mod(lzy[now]);
    104         return;
    105     }
    106     pushdown(now);
    107     int mid = (l[now] + r[now]) >> 1;
    108     if(R <= mid) update(L, R, now << 1);
    109     else if(L > mid) update(L, R, now << 1 | 1);
    110     else update(L, mid, now << 1), update(mid + 1, R, now << 1 | 1);
    111     sum[now] = sum[now << 1] + sum[now << 1 | 1]; Mod(sum[now]);
    112 }
    113 int query(int L, int R, int now)
    114 {
    115     if(L == l[now] && R == r[now]) return sum[now];
    116     pushdown(now);
    117     int mid = (l[now] + r[now]) >> 1;
    118     if(R <= mid) return query(L, R, now << 1);
    119     else if(L > mid) return query(L, R, now << 1 | 1);
    120     else return (query(L, mid, now << 1) + query(mid + 1, R, now << 1 | 1)) % mod;
    121 }
    122 
    123 void update_path(int x)
    124 {
    125     while(top[x] != 1)
    126     {        
    127         update(dfsx[top[x]], dfsx[x], 1);
    128         x = fa[top[x]];
    129     }
    130     update(dfsx[1], dfsx[x], 1);
    131 }
    132 int query_path(int x)
    133 {
    134     int ret = 0;
    135     while(top[x] != 1)
    136     {
    137         ret += query(dfsx[top[x]], dfsx[x], 1);
    138         Mod(ret);
    139         x = fa[top[x]];
    140     }
    141     ret += query(dfsx[1], dfsx[x], 1); Mod(ret);
    142     return ret;
    143 }
    144 
    145 struct Node
    146 {
    147     int id, flg, z;        
    148 };
    149 vector<Node> sec[maxn];
    150 int ans[maxn];
    151 
    152 int main()
    153 {
    154     n = read(); q = read();
    155     for(int i = 2; i <= n; ++i)
    156     {
    157         int x = read() + 1;
    158         v[x].push_back(i);
    159     }
    160     dfs1(1); top[1] = 1; dfs2(1);
    161     build(1, cnt, 1);
    162     for(int i = 1; i <= q; ++i) 
    163     {
    164         int L = read(), R = read(), z = read();
    165         L++; R++; z++;
    166         sec[L - 1].push_back((Node){i, -1, z});
    167         sec[R].push_back((Node){i, 1, z});
    168     }
    169     for(int i = 1; i <= n; ++i)
    170     {
    171         update_path(i);
    172         for(int j = 0; j < (int)sec[i].size(); ++j)
    173         {
    174             Node x = sec[i][j];
    175             ans[x.id] += x.flg * query_path(x.z);
    176             (ans[x.id] += mod) %= mod;
    177         }
    178     }
    179     for(int i = 1; i <= q; ++i) write(ans[i]), enter;
    180     return 0;
    181 }
    View Code
  • 相关阅读:
    我回来了.jpg
    NOIp2016 day1解题报告
    丢人笔记:黑科技——使用streambuf加速读入输出
    点分治总结
    改一下OI代码风格
    算法笔记:笛卡尔树
    复腱
    poj3348Cows 凸包板子
    线段树板子poj3468
    CH4201楼兰图腾
  • 原文地址:https://www.cnblogs.com/mrclr/p/9676607.html
Copyright © 2011-2022 走看看