给你一个 n 个点的有根树,根给出,和一个值域在 1~n 的数组。
然后 m 次操作,每次对于一个数组的区间 l~r,把它们的值都变成格子树上父亲的编号(如果是已经根就不变),或者求它们到根节点的路径长度的最小值。
rla1rmdq
题目大意
给你一个 n 个点的有根树,根给出,和一个值域在 1~n 的数组。
然后 m 次操作,每次对于一个数组的区间 l~r,把它们的值都变成格子树上父亲的编号(如果是已经根就不变),或者求它们到根节点的路径长度的最小值。
思路
考虑分块。
着重看大块的修改和查询。
考虑全局修改和全局查询。
发现因为是全部一起往上蹦,所以如果一个点蹦到了别的点曾经到过的,那它没必要再蹦了。
(永远有它的祖先比它更好)
那所以我们可以暴力蹦,然后暴力删,复杂度是 O(n+q) 的。
那么考虑到分块上,那我们考虑对于每一大块,算他的贡献。
那我们记录一个答案是整个大块的答案,然后大块修改就像我上面说的暴力改。
接着就是小块,先看修改,会发现一个问题。
就是它可能原本是被删掉的,然后它自己偷偷蹦上去了。
那你就 O(1) 把它补上就好。
那询问的话,你考虑弄一个 tag 表示整体加了多少次,再用一个 vali 表示数组 i 这个位置的跳了多少次(如果被删掉了就不会加)
那它的真实位置就是它的 tag−vali 级祖先,我们就跳到那里,然后把 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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 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)