【luogu CF1039E】Summer Oenothera Exhibition(贪心)(根号分治)(LCT)

Summer Oenothera Exhibition

题目链接:luogu CF1039E

题目大意

给你一个数组,然后每次问你一个 k,问你能把数组最少分成多少段,使得每一段的极差不超过 k。

思路

首先考虑对于一次询问怎么做。

考虑到一个贪心的想法,就是一个区间能往右扩一点是一点。
不难发现这样是正确的。

然后你考虑是否可以有一些东西优化这个过程。
那你每个地方你可以通过二分+区间求极差【可以用 ST 表】得到它作为一段的左边的话下一个段应该从哪里开始 nxti

然后你会发现如果我们把它连边,它可以相当于要求从 1n+1 点的路径长度。
那这个加边的我们可以用 DP 一下得到。
那考虑有没有一些东西方便扩展的,那 k 修改了边可能会变,那我们也可以用 LCT 来维护。

但是你每次可能都要更改每个边的 nxti 导致修改次数是 n2 复杂度是 n2logn 甚至不如暴力。
那我们考虑根号分治。

你会发现暴力跳的问题就是每次跳的距离太短,LCT 跳的问题就是修改的次数太多了。
那我们 B 的我们用 LCT,那这样每个数的 nxti 顶多修改 B 次。
然后大于的用暴力做,那每次这么跳的次数是 nB
B=n 就可以做到 O(nnlogn)

然后接着简单讲讲实现,考虑记录每个每个位置记录它是怎么跳的。
然后 LCT 的部分就不说了,说说怎么修改 nxti
考虑算出每个位置下一次修改是在那个询问,然后放进这个询问的 vector 里面。
然后每次看询问之间先把 vector 里面的搞出来修改了。

然后更新就是暴力加出位置,然后再用 lower_bound 得到下次在哪个询问。

代码

#include<cmath> #include<cstdio> #include<vector> #include<iostream> #include<algorithm> using namespace std; const int N = 1e5 + 100; const int B = 230; struct node { int id, k; }s[N]; int n, w, q, a[N], log2_[N], nxt[N]; int maxn[N][18], minn[N][18], xl[N]; int ans[N]; vector <int> st[N]; bool bl[N]; bool cmp(node x, node y) { return x.k < y.k; } int clac(int l, int r) { if (r == n + 1) return 2e9; int k = log2_[r - l + 1]; return max(maxn[l][k], maxn[r - (1 << k) + 1][k]) - min(minn[l][k], minn[r - (1 << k) + 1][k]); } int get_nxt(int now, int k) { int l = now, r = n, re; while (l <= r) { int mid = (l + r) >> 1; if (clac(now, mid) <= k) re = mid, l = mid + 1; else r = mid - 1; } return re + 1; } struct LCT { int sz[N], ls[N], rs[N], fa[N]; bool nrt(int x) {return ls[fa[x]] == x || rs[fa[x]] == x;} bool lrs(int x) {return ls[fa[x]] == x;} void up(int x) {sz[x] = sz[ls[x]] + sz[rs[x]] + 1;} void rotate(int x) { int y = fa[x], z = fa[y]; int b = lrs(x) ? rs[x] : ls[x]; if (z && nrt(y)) (lrs(y) ? ls[z] : rs[z]) = x; if (lrs(x)) rs[x] = y, ls[y] = b; else ls[x] = y, rs[y] = b; fa[x] = z; fa[y] = x; if (b) fa[b] = y; up(y); up(x); } void Splay(int x) { while (nrt(x)) { if (nrt(fa[x])) { if (lrs(x) == lrs(fa[x])) rotate(fa[x]); else rotate(x); } rotate(x); } } void access(int x) { int lst = 0; for (; x; lst = x, x = fa[x]) { Splay(x); rs[x] = lst; up(x); } } int find_root(int x) { access(x); Splay(x); while (ls[x]) x = ls[x]; Splay(x); return x; } void link(int x, int y) { access(x); fa[x] = y; } void cut(int x, int y) { access(x); Splay(y); fa[x] = 0; rs[y] = 0; up(y); } }T; int main() { scanf("%d %d %d", &n, &w, &q); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); for (int i = 1; i <= q; i++) { scanf("%d", &s[i].k); s[i].k = w - s[i].k; s[i].id = i; } sort(s + 1, s + q + 1, cmp); for (int i = 1; i <= q; i++) xl[i] = s[i].k; for (int i = 1; i <= n; i++) maxn[i][0] = minn[i][0] = a[i]; log2_[0] = -1; for (int i = 1; i <= n; i++) log2_[i] = log2_[i >> 1] + 1; for (int i = 1; i <= 17; i++) for (int j = 1; j + (1 << i) - 1 <= n; j++) { maxn[j][i] = max(maxn[j][i - 1], maxn[j + (1 << (i - 1))][i - 1]); minn[j][i] = min(minn[j][i - 1], minn[j + (1 << (i - 1))][i - 1]); } for (int i = 1; i <= n; i++) st[1].push_back(i), nxt[i] = i; for (int i = 1; i <= q; i++) { for (int j = 0; j < st[i].size(); j++) { int now = st[i][j], fr = nxt[now] + 1; T.cut(now, nxt[now]); while (fr <= n && fr - now <= B && clac(now, fr) <= s[i].k) fr++; if (fr - now > B) bl[now] = 1; else { int to = lower_bound(xl + 1, xl + q + 1, clac(now, fr)) - xl; nxt[now] = fr; T.link(now, nxt[now]); st[to].push_back(now); } } for (int j = 1; j <= n; j = get_nxt(j, s[i].k)) { if (!bl[j]) { T.access(j); T.Splay(j); ans[s[i].id] += T.sz[j] - 1; j = T.find_root(j); } if (j == n + 1) break; ans[s[i].id]++; } } for (int i = 1; i <= q; i++) printf("%d\n", ans[i] - 1); return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1039E.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(20)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
历史上的今天:
2021-03-24 【ybt金牌导航8-6-6】【HDU 3930】N次剩余(模数为素数)/ Broot
点击右上角即可分享
微信分享提示