敌兵布阵
大意:给你一个数列,和三个操作,
Query操作为查询从i到j之间的数的和
Add操作为第i个数加j
Sub操作为第i个数减j
要求每次Query操作你给他一个正确的回答
大概思路
直接线段树,区间维护的为当前区间的总和,
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <string>
using namespace std;
int n;
int arr[100020];
int sum[100020];
void build(int l, int r, int pos)
{
if(l == r) //不是区间也就是最下面的单个数的时候
{
sum[pos] = arr[l];
return;
}
int m = (l + r)/2;
build(l, m, pos*2); //维护左区间
build(m+1, r, pos*2+1); //右区间
sum[pos] = sum[pos*2] + sum[pos*2+1]; //二叉树转换成线性关系,双亲对应的左右子树
return;
}
void add(int i, int j, int l, int r, int pos)
{
if(i >= l && i <= r) // 如果要改变的i在当前区间,就加j
{
sum[pos] += j;
}
if(l == r) return; // 到最后return
int m = (l+r) / 2;
if(i <= m) add(i, j, l, m, pos*2);
if(i >= m+1) add(i, j, m+1, r, pos*2+1);
}
void sub(int i, int j, int l, int r, int pos)
{
if(i >= l && i <= r)
{
sum[pos] -= j;
}
if(l == r) return;
int m = (l+r) / 2;
if(i <= m) sub(i, j, l, m, pos*2);
if(i >= m+1) sub(i, j, m+1, r, pos*2+1);
}
int query(int i, int j, int l, int r, int pos)
{
if(i <= l && j >= r)
{
return sum[pos];
}
int ans = 0;
int m = (l + r) / 2;
if(i <= m) ans += query(i, j, l, m, pos*2);
if(j > m) ans += query(i, j, m+1, r, pos*2+1);
return ans;
}
int main()
{
int skip = 0;
int t;
cin >> t;
while(t--)
{
memset(arr, 0, sizeof arr); //初始化
memset(sum, 0, sizeof sum);
printf("Case %d:\n", ++skip);
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%d", &arr[i]); //储存数列
}
build(1, n, 1); //构建线段树
string a;
while(cin >> a && a != "End")
{
int x, y;
if(a == "Query")
{
scanf("%d%d", &x, &y);
printf("%d\n", query(x, y, 1, n, 1));
}
else if(a == "Add")
{
scanf("%d%d", &x, &y);
add(x, y, 1, n, 1);
}
else
{
scanf("%d%d", &x, &y);
sub(x, y, 1, n, 1);
}
}
}
return 0;
}