此题为基础的线段树。不用建树,可直接用数组模拟。
1 10 1 2 3 4 5 6 7 8 9 10 Query 1 3 Add 3 6 Query 2 7 Sub 10 2 Add 6 3 Query 3 10 End
Case 1: 6 33 59
#include <cstdio> #include <iostream> using namespace std; int T , n; const int maxn = 50001; int sum[maxn<<2]; //不用建树,直接以数组模拟 int arr[maxn]; void build(int l,int r,int k){ //k代表下标 if(l == r){ sum[k] = arr[l]; return; } int m = (l + r) / 2; build(l, m, k*2); //k的左孩子下标即为2k build(m+1,r,k*2 + 1); sum[k] = sum[k*2] + sum[k*2+1]; //在构造完当前树后,更新个数 } //在x出添加a个人。 添加区间为 (l,r) 从下标k开始 void update(int x,int a, int l, int r, int k){ if(l == r){ sum[k] += a; return; } int m = (l+r) / 2; if(x <= m){ update( x, a, l, m, k*2 ); }else update( x, a, m+1, r, k*2+1); sum[k] = sum[k*2] + sum[k*2+1]; //是一个自底向上的更新过程 } int query(int x,int y, int l, int r,int k){ if( x <= l && y >= r) return sum[k]; int m = (l + r) / 2; int ans = 0; if(x <= m) ans += query(x, y, l, m, k*2); if(y > m) ans += query(x,y, m+1, r, k*2+1); return ans; } int main() { //freopen("in.txt", "r", stdin); int x,a; scanf("%d",&T); for (int cas = 1 ; cas <= T ; cas ++) { printf("Case %d:\n",cas); scanf("%d",&n); for(int i=1; i<=n; i++){ scanf("%d", &arr[i]); } build(1 , n , 1); //初始化 char op[10]; while (scanf("%s",op)) { if(op[0] == 'E') break; scanf("%d %d", &x, &a); if(op[0] == 'A'){ update(x, a, 1, n, 1); //在整个区间(1,n) 从位置1出开始更新 } else if(op[0] == 'Q'){ //查询 //scanf("%d %d", &x, &a); printf("%d\n", query(x,a, 1, n, 1)); }else if(op[0] == 'S'){ update(x, -a, 1, n, 1); } } } return 0; }