【luogu P6779】rla1rmdq(分块)(树链剖分)

rla1rmdq

题目链接:luogu P6779

题目大意

给你一个 n 个点的有根树,根给出,和一个值域在 1~n 的数组。
然后 m 次操作,每次对于一个数组的区间 l~r,把它们的值都变成格子树上父亲的编号(如果是已经根就不变),或者求它们到根节点的路径长度的最小值。

思路

考虑分块。

着重看大块的修改和查询。
考虑全局修改和全局查询。

发现因为是全部一起往上蹦,所以如果一个点蹦到了别的点曾经到过的,那它没必要再蹦了。
(永远有它的祖先比它更好)
那所以我们可以暴力蹦,然后暴力删,复杂度是 O(n+q) 的。

那么考虑到分块上,那我们考虑对于每一大块,算他的贡献。
那我们记录一个答案是整个大块的答案,然后大块修改就像我上面说的暴力改。

接着就是小块,先看修改,会发现一个问题。
就是它可能原本是被删掉的,然后它自己偷偷蹦上去了。
那你就 O(1) 把它补上就好。

那询问的话,你考虑弄一个 tag 表示整体加了多少次,再用一个 vali 表示数组 i 这个位置的跳了多少次(如果被删掉了就不会加)
那它的真实位置就是它的 tagvali 级祖先,我们就跳到那里,然后把 vali=tag 就可以。
那如果它跳到了一个没有人到过的位置,那它就重新有效。

然后询问你也跳到真实位置然后贡献就可以啦。

然后至于怎么找 k 级祖先,直接树链剖分搞(轻重链就可以,没必要长链,你分块都已经带 log 了)

代码

#include<cmath> #include<cstdio> #include<iostream> #define ll long long using namespace std; const int N = 2e5 + 100; struct node { int x, to, nxt; }e[N << 1]; int n, m, rt, le[N], KK, B, a[N]; int bl[N], br[N], blo[N], Bn; struct Quest { int op, l, r; }q[N]; ll ans[N]; void add(int x, int y, int z) {e[++KK] = (node){z, y, le[x]}; le[x] = KK;} int fa[N], d[N]; ll deg[N]; struct SLPF { int sz[N], son[N], top[N], dfn[N], rnk[N]; void dfs0(int now, int father) { fa[now] = father; sz[now] = 1; for (int i = le[now]; i; i = e[i].nxt) if (e[i].to != father) { deg[e[i].to] = deg[now] + e[i].x; d[e[i].to] = d[now] + 1; dfs0(e[i].to, now); sz[now] += sz[e[i].to]; if (sz[e[i].to] > sz[son[now]]) son[now] = e[i].to; } } void dfs1(int now, int father) { dfn[now] = ++dfn[0]; rnk[dfn[0]] = now; if (son[now]) { top[son[now]] = top[now]; dfs1(son[now], now); } for (int i = le[now]; i; i = e[i].nxt) if (e[i].to != father && e[i].to != son[now]) { top[e[i].to] = e[i].to; dfs1(e[i].to, now); } } void Init() { dfs0(rt, 0); top[rt] = rt; dfs1(rt, 0); } int ask_k(int now, int k) { if (k >= d[now]) return rt; while (d[now] - d[top[now]] < k) { k -= d[now] - d[top[now]] + 1; now = fa[top[now]]; } return rnk[dfn[now] - k]; } }T; int val[N], sta[N]; bool in[N], met[N]; void slove(int L, int R) { for (int i = 1; i <= n; i++) val[i] = sta[i] = in[i] = met[i] = 0; ll an = 1e18; int tot = 0, tag = 0; for (int i = L; i <= R; i++) { if (met[a[i]]) continue; met[a[i]] = 1; in[i] = 1; sta[++tot] = i; an = min(an, deg[a[i]]); } for (int i = 1; i <= m; i++) { int l = max(L, q[i].l), r = min(R, q[i].r); if (l > r) continue; if (q[i].op == 1) { if (L == l && r == R) { int tmp = tot; tot = 0; tag++; for (int j = 1; j <= tmp; j++) { val[sta[j]]++; a[sta[j]] = fa[a[sta[j]]]; if (met[a[sta[j]]]) in[sta[j]] = 0; else { met[a[sta[j]]] = 1; sta[++tot] = sta[j]; an = min(an, deg[a[sta[j]]]); } } } else { for (int j = l; j <= r; j++) { a[j] = T.ask_k(a[j], (tag - val[j]) + 1); val[j] = tag; if (!met[a[j]]) { met[a[j]] = 1; if (!in[j]) sta[++tot] = j, in[j] = 1; an = min(an, deg[a[j]]); } } } } if (q[i].op == 2) { if (L == l && r == R) ans[i] = min(ans[i], an); else { for (int j = l; j <= r; j++) { a[j] = T.ask_k(a[j], tag - val[j]); val[j] = tag; ans[i] = min(ans[i], deg[a[j]]); } } } } } int main() { scanf("%d %d %d", &n, &m, &rt); for (int i = 1; i < n; i++) { int x, y, z; scanf("%d %d %d", &x, &y, &z); add(x, y, z); add(y, x, z); } for (int i = 1; i <= n; i++) scanf("%d", &a[i]); T.Init(); B = sqrt(n); for (int i = 1; i <= n; i++) { blo[i] = (i - 1) / B + 1; if (!bl[blo[i]]) bl[blo[i]] = i; br[blo[i]] = i; } Bn = blo[n]; for (int i = 1; i <= m; i++) { int op, l, r; scanf("%d %d %d", &op, &l, &r); q[i] = (Quest){op, l, r}; ans[i] = 1e18; } for (int i = 1; i <= Bn; i++) slove(bl[i], br[i]); for (int i = 1; i <= m; i++) if (q[i].op == 2) printf("%lld\n", ans[i]); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_P6779.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(40)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-09-30 【jzoj 7207】缘木求鱼(数论)(高精)
2021-09-30 【luogu U137469】分肉(结论)
2021-09-30 【ARC 127B】Ternary Strings(构造)
2021-09-30 【nowcoder 225285】牛牛防疫情(网络流)
2021-09-30 【nowcoder 225284】牛牛小数点(结论)(数学)
2021-09-30 【luogu U138101】字符串水题(SAM)(树状数组)
2021-09-30 【ybt高效进阶 21165 / 150C】【nowcoder 1103B】树上交集 / 路径计数机(换根DP)(树形DP)
点击右上角即可分享
微信分享提示