[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

 

posted @ 2018-09-19 19:42  mrclr  阅读(291)  评论(1编辑  收藏  举报