题意:
区间查询,单点修改
第一行一个整数T,表示有T组数据。
每组数据第一行一个正整数N(N<=50000),表示敌人有N个工兵营地,接下来有N个正整数,第i个正整数ai代表第i个工兵 营地里开始时有ai个人(1<=ai<=50)。
接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
数据范围:
1S
(N 5e4)
每组数据最多有40000条命令
Q +A +S = 4e4
思路:
区间查询,单点修改
1)线段树
AC:
#include
#include
#include
#include
using namespace std;
const int MAX_LEN = 4e5;
int N, T;
int arr[MAX_LEN + 20];
int seg_tree[MAX_LEN << 2];
int lazy[MAX_LEN << 2];
void push_up(int root) {
seg_tree[root] = seg_tree[root << 1 ] + seg_tree[root << 1 | 1];
}
void push_down(int root, int L, int R) {
if(lazy[root]) {
int mid = (L + R) >> 1;
lazy[root << 1] += lazy[root];
lazy[root << 1 | 1] += lazy[root];
seg_tree[root << 1] += lazy[root] * (mid - L + 1); //左子树上的和加上lazy值
seg_tree[root << 1 | 1] += lazy[root] * (R - mid); //右子树上的和+上lazy值
lazy[root] = 0;
}
}
void build (int root, int L, int R) {
if (L == R) {
seg_tree[root] = arr[L];
return ;
}
int mid = (L + R) / 2;
// [ L, mid] 左子树, [mid + 1, r]右子树
build(root << 1, L, mid);
build(root << 1 | 1, mid + 1, R);
push_up(root);
//对与当前的根节点,把当前的根节点的左右子树都算出来后,再更新它的值
// 沿路回溯, 回溯到点root 时, 都是被 [ L, R] 或者其子区间影响到的点,边回溯边更新
}
//点修改
void update (int root, int L, int R,int pos, int val) {
if(L == R) {
seg_tree[root] += val;
return ;
}
int mid = (L + R) / 2;
// 左区间
if (pos <= mid) update (root << 1, L, mid, pos, val);
//右区间
else update (root << 1 | 1, mid + 1, R, pos, val);
push_up(root);
}
//区间查旬
int query (int root, int L, int R,int LL ,int RR) {
if( L >= LL && R <= RR) {
return seg_tree[root];
}
push_down(root, L, R); //每次访问都去检查Lazy标记
long long Ans = 0;
int mid = (L + R) >> 1;
if(LL <= mid) Ans += query(root << 1, L, mid, LL, RR);
if(RR > mid) Ans += query(root << 1|1, mid + 1, R, LL, RR);
return Ans;
}
//区间修改
//void update (int root, int L, int R, int LL, int RR, int val) {
// //[LL, RR] 为即将要更新的区间
// if(LL <= L && R <= RR) {
// lazy[root] += val;
// seg_tree[root] += val * (R - L + 1);
// return;
// }
// //更新子树
// push_down(root, L, R);
// int mid = (L + R) >> 1;
// if(LL <= mid) update(root << 1, L, mid, LL, RR, val);
// if(RR > mid) update(root << 1 | 1, mid + 1, R, LL, RR, val);
// //更新父节点
// push_up(root);
//}
int main(){
//freopen("in.txt", "r", stdin);
scanf("%d", &T);
int Case = 1;
while(T--) {
char ch[20];
scanf("%d", &N);
for(int i = 1; i <= N; ++i) {
scanf("%d", &arr[i]);
}
build(1, 1, N);
printf("Case %d:\n", Case++);
while(scanf("%s", &ch)){
int L, R, C;
if(ch[0] == 'Q') {
scanf("%d%d", &L, &R);
printf("%d\n", query(1, 1, N, L, R));
} else if(ch[0] == 'A'){
scanf("%d%d", &L, &C);
update(1, 1, N, L, C);
} else if(ch[0] == 'S') {
scanf("%d%d", &L, &C);
update(1, 1, N, L, -C);
}else {
break;
}
}
}
return 0;
}