P4211 [LNOI2014]LCA(离线 + 在线 做法)
P4211 [LNOI2014]LCA
有一棵根節(jié)點為111樹,有mmm次詢問,每次給定l,r,zl, r, zl,r,z,輸出∑i=lrdep[lca(i,z)]\sum\limits_{i = l} ^{r} dep[lca(i, z)]i=l∑r?dep[lca(i,z)]。
乍一看這題好像無從下手,仔細想想lca(i,z)lca(i, z)lca(i,z)有何性質(zhì),不難發(fā)現(xiàn)lca(i,z)lca(i, z)lca(i,z)一定是在1?>z1->z1?>z的路徑上的,
那么我們的答案求解就可以轉(zhuǎn)換為每次對i?>1i->1i?>1路徑上的點加一,求z?>1z->1z?>1上路徑上的點的和即為我們要求的答案。
考慮如何優(yōu)化這一過程:
離線求解:
將每個詢問(l,r,z)(l, r, z)(l,r,z)拆分成(1,l?1,z),(1,r,z)(1, l - 1, z), (1, r, z)(1,l?1,z),(1,r,z),那么答案就為(1,r,z)?(1,l?1,z)(1, r, z) - (1, l - 1, z)(1,r,z)?(1,l?1,z)了,
我們將所有拆分后詢問按照rrr排個序,從小到大每次插入點iii,如果當(dāng)前插入的點iii等于每個詢問的rrr則統(tǒng)計一次答案,
兩點之間點權(quán)的信息更新可以考慮樹剖,注意答案的加減,最后輸出答案即可,整體復(fù)雜度O(nlog?nlog?n)O(n \log n \log n)O(nlognlogn)。
#include <bits/stdc++.h> #define mid (l + r >> 1) #define lson rt << 1, l, mid #define rson rt << 1 | 1, mid + 1, r #define ls rt << 1 #define rs rt << 1 | 1using namespace std;const int N = 1e5 + 10, mod = 201314;int head[N], to[N], nex[N], cnt = 1;int fa[N], dep[N], sz[N], son[N], rk[N], id[N], top[N], tot;int sum[N << 2], lazy[N << 2], ans[N], n, m;struct Res {int u, v, id;bool operator < (const Res &t) {return u < t.u;} }a[N];void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }void dfs1(int rt, int f) {fa[rt] = f, dep[rt] = dep[f] + 1, sz[rt] = 1;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == f) {continue;}dfs1(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[son[rt]] < sz[to[i]]) {son[rt] = to[i];}} }void dfs2(int rt, int tp) {top[rt] = tp, rk[++tot] = rt, id[rt] = tot;if (!son[rt]) {return ;}dfs2(son[rt], tp);for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa[rt] || to[i] == son[rt]) {continue;}dfs2(to[i], to[i]);} }void push_up(int rt) {sum[rt] = (sum[ls] + sum[rs]) % mod; }void push_down(int rt, int l, int r) {if (lazy[rt]) {lazy[ls] = (lazy[ls] + lazy[rt]) % mod, lazy[rs] = (lazy[rs] + lazy[rt]) % mod;sum[ls] = (sum[ls] + 1ll * (mid - l + 1) * lazy[rt]) % mod;sum[rs] = (sum[rs] + 1ll * (r - mid) * lazy[rt]) % mod;lazy[rt] = 0;} }void update(int rt, int l, int r, int L, int R, int v) {if (l >= L && r <= R) {lazy[rt] = (lazy[rt] + 1) % mod;sum[rt] = (sum[rt] + r - l + 1) % mod;return ;}push_down(rt, l, r);if (L <= mid) {update(lson, L, R, v);}if (R > mid) {update(rson, L, R, v);}push_up(rt); }int query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {return sum[rt];}push_down(rt, l, r);int ans = 0;if (L <= mid) {ans = query(lson, L, R);}if (R > mid) {ans = (ans + query(rson, L, R)) % mod;}return ans; }void update(int rt) {while (rt) {update(1, 1, n, id[top[rt]], id[rt], 1);rt = fa[top[rt]];} }int query(int rt) {int ans = 0;while (rt) {ans = (ans + query(1, 1, n, id[top[rt]], id[rt])) % mod;rt = fa[top[rt]];}return ans; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);scanf("%d %d", &n, &m);for (int i = 2, fa; i <= n; i++) {scanf("%d", &fa);add(fa + 1, i);}dfs1(1, 0);dfs2(1, 1);for (int i = 1, l, r, u; i <= m; i++) {scanf("%d %d %d", &l, &r, &u);l++, r++, u++;a[i * 2 - 1] = {l - 1, u, i * 2 - 1};a[i * 2] = {r, u, i * 2};}sort(a + 1, a + 1 + 2 * m);int cur = 1;while (cur <= 2 * m && a[cur].u == 0) {cur++; }for (int i = 1; i <= n; i++) {update(i);while (cur <= 2 * m && a[cur].u == i) {int res = query(a[cur].v);if (a[cur].id & 1) {ans[a[cur].id + 1 >> 1] = (ans[a[cur].id + 1 >> 1] + mod - res) % mod;}else {ans[a[cur].id >> 1] = (ans[a[cur].id >> 1] + res) % mod;}cur++;}}for (int i = 1; i <= m; i++) {printf("%d\n", ans[i]);}return 0; }在線求解:
考慮主席樹,第iii棵主席樹為前i?1i - 1i?1棵主席樹的信息 + 節(jié)點編號為iii的點到根節(jié)點權(quán)值都+1+1+1的信息。
不難想到,最后我們的答案就是在[l,r][l, r][l,r]區(qū)間的主席樹上查詢在1?>z1->z1?>z之間的點的權(quán)值和。
主席樹上打lazylazylazy,空間按道理應(yīng)該是O(nlog?nlog?n)O(n \log n \log n)O(nlognlogn)級別的,支持在線求解時間復(fù)雜度也是O(nlog?nlog?n)O(n \log n \log n)O(nlognlogn)級別的。
#include <bits/stdc++.h>using namespace std;const int N = 5e4 + 10, mod = 201314;int head[N], to[N], nex[N], cnt = 1;int fa[N], son[N], sz[N], top[N], dep[N], rk[N], id[N], tot;int root[N], ls[N * 200], rs[N * 200], sum[N * 200], lazy[N * 200], n, m, num;void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }void dfs1(int rt, int f) {fa[rt] = f, dep[rt] = dep[f] + 1, sz[rt] = 1;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == f) {continue;}dfs1(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[son[rt]] < sz[to[i]]) {son[rt] = to[i];}} }void dfs2(int rt, int tp) {top[rt] = tp, rk[++tot] = rt, id[rt] = tot;if (!son[rt]) {return ;}dfs2(son[rt], tp);for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa[rt] || to[i] == son[rt]) {continue;}dfs2(to[i], to[i]);} }void update(int &rt, int pre, int l, int r, int L, int R, int v) {rt = ++num;ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre], lazy[rt] = lazy[pre];sum[rt] = (sum[rt] + 1ll * (min(r, R) - max(l, L) + 1) * v) % mod;if (l >= L && r <= R) {lazy[rt] = (lazy[rt] + v) % mod;return ;}int mid = l + r >> 1;if (L <= mid) {update(ls[rt], ls[pre], l, mid, L, R, v);}if (R > mid) {update(rs[rt], rs[pre], mid + 1, r, L, R, v);} }int query(int rt1, int rt2, int l, int r, int L, int R) {if (l >= L && r <= R) {return (sum[rt2] - sum[rt1] + mod) % mod;}int mid = l + r >> 1, ans = (1ll * (min(r, R) - max(l, L) + 1) * (lazy[rt2] - lazy[rt1]) % mod + mod) % mod;if (L <= mid) {ans = (ans + query(ls[rt1], ls[rt2], l, mid, L, R)) % mod;}if (R > mid) {ans = (ans + query(rs[rt1], rs[rt2], mid + 1, r, L, R)) % mod;}return ans; }int query(int l, int r, int rt) {int ans = 0;while (rt) {ans = (ans + query(root[l], root[r], 1, n, id[top[rt]], id[rt])) % mod;rt = fa[top[rt]];}return ans; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d", &n, &m);for (int i = 2, fa; i <= n; i++) {scanf("%d", &fa);add(fa + 1, i);}dfs1(1, 0);dfs2(1, 1);for (int i = 1; i <= n; i++) {int rt = i;root[i] = root[i - 1];while (rt) {update(root[i], root[i], 1, n, id[top[rt]], id[rt], 1);rt = fa[top[rt]];}}for (int i = 1, l, r, rt; i <= m; i++) {scanf("%d %d %d", &l, &r, &rt);l++, r++, rt++;printf("%d\n", query(l - 1, r, rt));}return 0; }總結(jié)
以上是生活随笔為你收集整理的P4211 [LNOI2014]LCA(离线 + 在线 做法)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: min_25 推导及例题总结
- 下一篇: #6073. 「2017 山东一轮集训