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