【NOI2022省选挑战赛 Contest5 A】我的 OI(线段树)

我的 OI

题目链接:NOI2022省选挑战赛 Contest5 A

题目大意

给你一个序列,然后每个位置有 a,b 两个值,如果你当前分数大于 a 就可以加上 b 的分数。
然后多组询问每次给你一开始的分数,起点和终点,然后问你从起点走到终点你的分数会变成多少。

思路

我们考虑先单独考虑一个位置,可以发现它可以表示成一个分段函数,两段。

然后你试着用线段树,然后想如何合并两段。
你可以发现你可以用两个指针扫,然后按着那个加贡献的基准(这个不是从当前位置,而是这个区间的左边之前)从小到大放,然后每个要把前面能有的贡献都要加上。
然后这么搞之后如果你把全部都放上,你会发现有一部分可能不是递增的,然后我们要弄个类似单调队列之类的因为毕竟是后面的贡献大。

然后在询问的时候,线段树可以把询问分成 log 个块,然后我们从前往后看每个块,然后可以用二分找到贡献的位置,然后每次贡献即可。

代码

#include<cstdio> #include<vector> #include<climits> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N = 500000 + 100; int n, q, a[N], b[N], l, r; ll x; struct XD_tree { vector <pair<ll, ll> > f[N << 2], tmp; void up(int now) { int x = 0, y = 0; f[now].clear(); tmp.clear(); while (x < f[now << 1].size() && y < f[now << 1 | 1].size()) { if (f[now << 1][x].first + f[now << 1][x].second < f[now << 1 | 1][y].first) { tmp.push_back(make_pair(f[now << 1][x].first, f[now << 1][x].second + (y ? f[now << 1 | 1][y - 1].second : 0))); x++; } else { tmp.push_back(make_pair(f[now << 1 | 1][y].first - (x ? f[now << 1][x - 1].second : 0), f[now << 1 | 1][y].second + (x ? f[now << 1][x - 1].second : 0))); y++; } } while (x < f[now << 1].size()) { tmp.push_back(make_pair(f[now << 1][x].first, f[now << 1][x].second + (y ? f[now << 1 | 1][y - 1].second : 0))); x++; } while (y < f[now << 1 | 1].size()) { tmp.push_back(make_pair(f[now << 1 | 1][y].first - (x ? f[now << 1][x - 1].second : 0), f[now << 1 | 1][y].second + (x ? f[now << 1][x - 1].second : 0))); y++; } for (int i = 0; i < tmp.size(); i++) { while (f[now].size() && f[now][f[now].size() - 1].first >= tmp[i].first) f[now].pop_back(); f[now].push_back(tmp[i]); } } void build(int now, int l, int r) { if (l == r) { f[now].push_back(make_pair(a[l] + 1, b[l])); return ; } int mid = (l + r) >> 1; build(now << 1, l, mid); build(now << 1 | 1, mid + 1, r); up(now); } void query(int now, int l, int r, int L, int R, ll &x) { if (L <= l && r <= R) { if (upper_bound(f[now].begin(), f[now].end(), make_pair(x, LLONG_MAX)) != f[now].begin()) x += (*(upper_bound(f[now].begin(), f[now].end(), make_pair(x, LLONG_MAX)) - 1)).second; return ; } int mid = (l + r) >> 1; if (L <= mid) query(now << 1, l, mid, L, R, x); if (mid < R) query(now << 1 | 1, mid + 1, r, L, R, x); } }T; int main() { scanf("%d %d", &n, &q); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); } for (int i = 1; i <= n; i++) { scanf("%d", &b[i]); } T.build(1, 1, n); while (q--) { scanf("%d %d %lld", &l, &r, &x); T.query(1, 1, n, l, r, x); printf("%lld\n", x); } return 0; }

__EOF__

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