题解:AT_arc210_a [ARC210A] Always Increasing
GLr137_2025BL · · 题解
::::info[说在前面] 这道题目其实非常的简单,质量还行,动点脑子就行了。但是我好像是讲得最详细的一个,就是给像我一样菜的人一点有用的帮助。有些语句可能虽然我竭尽全力用最形象的语言来讲但还是难以理解,可以多读一读想一想,最后恳请您阅读到底。 ::::
题意是给定
我们考虑寻找其中的规律。
首先,我们尝试能否还原最终所有操作后的数列?(这一步比较难想,需要仔细读题并想一会儿才能想到,详细看下面)
不难发现,如果当前数组满足上文的升序条件。每一次增加某一项的时候,前面的不会受到任何影响,因为增加的数是正数。而这个数后面的数中如果出现了小于等于这个数的情况的话,那么说明升序被破坏了,只需要将后面的所有数跟随着增加同样的某个值使得依然升序即可。这一点只要想到了,基本就完成思路了,就是这一点可能会兜几圈才到,但应该是可以想到的。
我们来讨论具体实现细节。由于在一次都没有运算前,根据上文所说的性质,我们要保证数组满足那个升序条件。那必然数组先设为
那么直接一个一个加太慢了,我们便想到用树状数组来维护,树状数组都会吧?不会去 某个地方 学习。我们增加的时候运用树状数组,只增加
最后,我们获得了对应的最终数组,然后我们用这个数组的和减去所有增加值之和不久还原初始最小序列的和了吗?这是一种逆推的思路,极其巧妙。
::::success[AC 代码]
# include <bits/stdc++.h>
# define int long long
# define MAXN 200005
using namespace std;
inline int read (){
int x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-'){f = -1;} ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - 48; ch = getchar();}
return x * f;
}
int n, q, ans, sumz, I[MAXN], x[MAXN], sz[MAXN], tree[MAXN];
int lowbit (int x){
return x & -x;
}
void add (int k, int x){
while (k <= n){
tree[k] += x;
k += lowbit(k);
}
}
int sum (int k){
int s = 0;
while (k >= 1){
s += tree[k];
k -= lowbit(k);
}
return s;
}
signed main (){
n = read(), q = read();
for (int i = 1; i <= n; i++){
sz[i] = i;
}
for (int i = 1; i <= q; i++){
I[i] = read(), x[i] = read();
sz[I[i]] += x[i];
sumz += x[i];
if (sz[I[i]] + sum(I[i]) >= sz[I[i] + 1] + sum(I[i] + 1)){
add(I[i] + 1, sz[I[i]] + sum(I[i]) - (sz[I[i] + 1] + sum(I[i] + 1)) + 1);
}
}
for (int i = 1; i <= n; i++){
sz[i] += sum(i);
ans += sz[i];
}
cout << ans - sumz;
return 0;
}
::::
代码仅供参考,抄袭必有后报。