|
|
#include <iostream>
|
|
|
#include <cstring>
|
|
|
#include <algorithm>
|
|
|
|
|
|
using namespace std;
|
|
|
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 << 3) + (x << 1) + (ch ^ 48);
|
|
|
ch = getchar();
|
|
|
}
|
|
|
return x * f;
|
|
|
}
|
|
|
|
|
|
const int N = 1e5 + 10;
|
|
|
int n;
|
|
|
int t[N << 1];
|
|
|
|
|
|
void build() {
|
|
|
for (int i = 0; i < n; i++) t[n + i] = read();
|
|
|
for (int i = n - 1; i; i--) t[i] = t[i << 1] + t[i << 1 | 1];
|
|
|
}
|
|
|
|
|
|
void modify(int l, int r, int value) {
|
|
|
for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
|
|
|
if (l & 1) t[l++] += value;
|
|
|
if (r & 1) t[--r] += value;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
//区间查询
|
|
|
int query(int l, int r) { // sum on interval [l, r)
|
|
|
int res = 0;
|
|
|
for (l += n, r += n; l < r; l >>= 1, r >>= 1) {
|
|
|
//① 如果l是奇数,l是父亲的右孩子(看一下上面的图,确实是右孩子)
|
|
|
// (1) 此时,只有它自己有用,它的父亲不包含在查询区间内。自己加上,把略过即可
|
|
|
// (2) 怎么略过呢?巧妙的办法:本轮次不加自己父亲,下软移动到右边的兄弟节点的父亲上去! l= (l+1) >> 1
|
|
|
//② 如果l是偶数,那么l就是父亲的左儿子,整个区间完整命中,直接研究它父亲的sum即可, l>>=1
|
|
|
if (l & 1) res += t[l++];
|
|
|
|
|
|
//与上面代码对称的写法
|
|
|
if (r & 1) res += t[--r];
|
|
|
}
|
|
|
return res;
|
|
|
}
|
|
|
int main() {
|
|
|
//文件输入输出
|
|
|
#ifndef ONLINE_JUDGE
|
|
|
freopen("zkw_Study_2.in", "r", stdin);
|
|
|
#endif
|
|
|
n = read();
|
|
|
build();
|
|
|
|
|
|
modify(0, 1, 1); //修改[0,1)也是就是修改下标0的值为1
|
|
|
for (int i = n; i < 2 * n; i++) printf("%d ", t[i]);
|
|
|
puts("");
|
|
|
|
|
|
printf("%d\n", query(1, 3)); //下标从0开始,查询[1,3)=3
|
|
|
return 0;
|
|
|
//感悟:这东西区间修改,区间查询就OK了,没有什么单点修改,单点查询,直接上区间修改、区间查询不就行了吗?
|
|
|
} |