Codeforces Round #489 (Div. 2) E. Nastya and King-Shamans(线段树)

题意

给出一个长度为 n 的序列 {ai} , 现在会进行 m 次操作 , 每次操作会修改某个 ai 的值 ,

在每次操作完后你需要判断是否存在一个位置 i, 满足 ai=j=1i1aj 并求任意一个 i .

n,m105,0ai109

题解

考虑一个暴力,不妨首先从 i=1 开始判断是否合法,由于 ai 是单调不降的,符合条件的 ai 一定大于等于当前前缀和。

每次用线段树找到大于等于当前前缀和的最左边的 ai 并判断是否合法。(这个位置一定要在前缀和的右边)

这样为什么是对的呢,因为你下一次的起点不可能存在与现在的位置到下次位置之间的任意位置。

(因为每个值都不会 当前的前缀和)

这样做就是对的了,因为如果新的 ai 不合法,那么当前前缀和至少会达到上一次的两倍。

于是这样子查找的次数就是 O(logw) 的 , 总复杂度是 O(mlognlogw) .

总结

考虑一类题对于权值翻倍时候的复杂度是 O(logw) 的,例如 ZJOI2018 历史

代码

#include <bits/stdc++.h> #define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i) #define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i) #define Set(a, v) memset(a, v, sizeof(a)) #define Cpy(a, b) memcpy(a, b, sizeof(a)) #define debug(x) cout << #x << ": " << (x) << endl #define DEBUG(...) fprintf(stderr, __VA_ARGS__) using namespace std; template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;} template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;} inline int read() { int x(0), sgn(1); char ch(getchar()); for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1; for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48); return x * sgn; } void File() { #ifdef zjp_shadow freopen ("E.in", "r", stdin); freopen ("E.out", "w", stdout); #endif } const int N = 2e5 + 1e3; typedef long long ll; #define lson o << 1, l, mid #define rson o << 1 | 1, mid + 1, r int a[N]; template<int Maxn> struct Segment_Tree { int maxv[Maxn]; ll sumv[Maxn]; inline void Push_Up(int o) { sumv[o] = sumv[o << 1] + sumv[o << 1 | 1]; maxv[o] = max(maxv[o << 1], maxv[o << 1 | 1]); } void Build(int o, int l, int r) { if (l == r) return (void)(maxv[o] = sumv[o] = a[l]); int mid = (l + r) >> 1; Build(lson); Build(rson); Push_Up(o); } void Update(int o, int l, int r, int up, int uv) { if (l == r) return (void)(sumv[o] = maxv[o] = uv); int mid = (l + r) >> 1; if (up <= mid) Update(lson, up, uv); else Update(rson, up, uv); Push_Up(o); } ll Sum(int o, int l, int r, int qr) { if (r <= qr) return sumv[o]; int mid = (l + r) >> 1; return Sum(lson, qr) + (qr > mid ? Sum(rson, qr) : 0); } int Find(int o, int l, int r, int ql, ll val) { if (ql > r || maxv[o] < val) return 0; if (l == r) return l; int mid = (l + r) >> 1; int pos = Find(lson, ql, val); return pos ? pos : Find(rson, ql, val); } }; Segment_Tree<N << 2> T; int n, q; inline int Solve() { if (a[1] == 0) return 1; int cur = 1; ll sum = a[1]; for (;;) { int pos = T.Find(1, 1, n, cur + 1, sum); if (!pos) return -1; sum = T.Sum(1, 1, n, (cur = pos) - 1); if (sum == a[pos]) return pos; sum += a[pos]; } } int main () { File(); n = read(), q = read(); For (i, 1, n) a[i] = read(); T.Build(1, 1, n); For (i, 1, q) { int pos = read(), val = read(); T.Update(1, 1, n, pos, a[pos] = val); printf ("%d\n", Solve()); } return 0; }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/9743561.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(230)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示