JOISC2024 Day1A Fish 另解
题目大意
给定一个长度为
的序列 , 次询问区间 ,表示若初始有一个长度为 的全 数组 ,每次操作可单点加 或者将一个后缀加上 ,求最少单点加操作次数使得 ,或输出无解。
数据范围:, 。
思路分析
考虑将操作倒序进行,那么相当于将每次询问的子段进行最少的单点减
考虑使用线段树维护,那么我们可以先将拆分出的每个段内先进行调整后再合并调整,例如段
调整可以被拆成若干个后缀减
将
而我们要进行
时间复杂度为
代码呈现
实现了
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
long long a[N], D;
vector<long long> arr[1 << 20];
long long opt[1 << 20], sc[1 << 20], pos[1 << 20];
vector< tuple<long long, long long, long long> > z[1 << 20];
void upd(int k) {
for (int i = 0; i + 1 < (int)arr[k].size(); ++i) {
z[k].push_back({sc[k], i + 1, pos[k]});
sc[k] += (arr[k][i] - arr[k][i + 1]) / D;
pos[k] += (arr[k][i] - arr[k][i + 1]) / D * (i + 1);
}
}
void build(int k, int l, int r) {
if (l == r) {
arr[k].push_back(a[l]);
upd(k);
return;
}
int mid = (l + r) >> 1;
build(k << 1, l, mid);
build(k << 1 | 1, mid + 1, r);
opt[k] = opt[k << 1] + opt[k << 1 | 1];
arr[k] = arr[k << 1 | 1];
for (auto x : arr[k << 1]) {
if (x > arr[k].back()) {
opt[k] += ((x - arr[k].back() + D - 1) / D);
x -= D * ((x - arr[k].back() + D - 1) / D);
}
arr[k].push_back(x);
}
upd(k);
}
pair<long long, long long> query(int k, int l, int r, int x, int y, long long w) {
if (l >= x && r <= y) {
if (w >= arr[k][0]) return {arr[k].back(), opt[k]};
long long o = (arr[k][0] - w + D - 1) / D;
if (sc[k] <= o) {
return {arr[k].back() - (o - sc[k]) * D, opt[k] + pos[k] + (o - sc[k]) * (r - l + 1)};
}
auto [a, b, c] = *--upper_bound(z[k].begin(), z[k].end(), tuple<long long, long long, long long>{o, 0, 0});
return {arr[k].back(), opt[k] + c + (o - a) * b};
}
int mid = (l + r) >> 1;
if (y <= mid) return query(k << 1, l, mid, x, y, w);
if (x > mid) return query(k << 1 | 1, mid + 1, r, x, y, w);
pair<long long, long long> rs = query(k << 1 | 1, mid + 1, r, x, y, w);
pair<long long, long long> ls = query(k << 1, l, mid, x, y, rs.first);
return {ls.first, ls.second + rs.second};
}
signed main() {
int n; scanf("%d%lld", &n, &D);
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
build(1, 1, n);
int q; scanf("%d", &q);
while (q--) {
int l, r; scanf("%d%d", &l, &r);
auto [x, y] = query(1, 1, n, l, r, 1e18);
if (x < 0) puts("-1");
else printf("%lld\n", y);
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现