一. 原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
二. 题目大意:简化为模型为:给一个区间,区间上每个数可看做容器,对容器有增加,减少,查询3种操作。增加减少只针对一个容器,查询可以多个容器连在一起。每次查询输出查询区间共放有多少东西。
三. 解题思路:暴力肯定超时(50000*40000)。线段树,最基础的单点更新。线段树,也就是区间树,树的每个节点代表一个区间,根节点代表最大的区间[0, N],左子树代表[0, mid],右子树代表[mid+1, r],以此类推。每个节点增加一个域代表当前区间共有多少士兵。然后就是线段树基本操作,建立树,单点更新,查询。
四. 代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX_N = 50010,
INF = 0x3f3f3f3f;
#define LC(t) t<<1
#define RC(t) t<<1|1
struct node
{
int l, r, cnt;
};
node seTree[4*MAX_N];
void build(int l, int r, int idx)
{
seTree[idx].l = l;
seTree[idx].r = r;
seTree[idx].cnt = 0;
if(l == r)
return;
int mid = (l+r)>>1;
build(l, mid, LC(idx));
build(mid+1, r, RC(idx));
}
void add(int idx, int pos, int num)
{
int l = seTree[idx].l,
r = seTree[idx].r;
if(l <= pos && r >= pos){
seTree[idx].cnt += num;
if(l == r)
return;
add(LC(idx), pos, num);
add(RC(idx), pos, num);
}
}
int query(int l, int r, int idx)
{
int lSide = seTree[idx].l,
rSide = seTree[idx].r;
if(lSide == l && rSide == r)
return seTree[idx].cnt;
int mid = (lSide+rSide)>>1;
if(lSide <= l && mid >= r)
return query(l, r, LC(idx));
if(mid+1 <= l && rSide >= r)
return query(l, r, RC(idx));
if(lSide <= l && rSide >= r){
return query(l, mid, LC(idx)) +
query(mid+1, r, RC(idx));
}
}
int main()
{
//freopen("in.txt", "r", stdin);
int T, N, i, num, kase = 1;
char command[11];
scanf("%d", &T);
while(T--){
printf("Case %d:\n", kase++);
scanf("%d", &N);
build(0, N, 1);
for(i = 1; i <= N; i++){
scanf("%d", &num);
add(1, i, num);
}
while(~scanf("%s", command)){
if(command[0] == 'E')
break;
int a, b;
scanf("%d %d", &a, &b);
switch(command[0])
{
case 'A':
add(1, a, b);
break;
case 'S':
add(1, a, -b);
break;
case 'Q':
printf("%d\n", query(a, b, 1));
break;
}
}
}
return 0;
}
法二:树状数组,由于每个整数都可以表示为2的幂次方的和,所以如果对于当前数son,定义father = son+2^k,其中k为son转化为二进制之后末尾0的个数,这样在整数集上刚好存在一一对应的关系。树的每个节点表示从1到该节点对于的值的和。一个树状数组只能单点更新和求前缀和。
#include <cstdio>
#include <cstring>
using namespace std;
const int MAX_N = 50500;
const int INF = 0x3f3f3f3f;
int tree[MAX_N], N;
int lowbit(int x)
{
return x & (-x);
}
void update(int pos, int ele)
{
while(pos <= N){
tree[pos] += ele;
pos += lowbit(pos);
}
}
int query(int pos)
{
int res = 0;
while(pos > 0){
res += tree[pos];
pos -= lowbit(pos);
}
return res;
}
int main()
{
//freopen("in.txt", "r", stdin);
int T, i, ele, a, b, kase = 1;
char str[10];
scanf("%d", &T);
while(T--){
printf("Case %d:\n", kase++);
memset(tree, 0, sizeof(tree));
scanf("%d", &N);
for(i = 1; i <= N; i++){
scanf("%d", &ele);
update(i, ele);
}
while(~scanf("%s", str) && str[0]!='E'){
scanf("%d %d", &a, &b);
switch(str[0])
{
case 'Q':
printf("%d\n", query(b)-query(a-1));
break;
case 'A':
update(a, b);
break;
case 'S':
update(a, -b);
break;
}
}
}
return 0;
}