http://acm.hdu.edu.cn/showproblem.php?pid=1166
题意:有n个营地,三个操作,Add x y代表在x营地增加y人,Sub x y代表在x营地减少y人,Query x y代表查询[x,y]区间内营地人数之和。
树状数组:
思路:由于只涉及单点更新和区间求和,树状数组也可以。
树状数组里的sum求的是1~n-1的和,那么求区间和就是sum(y)-sum(x-1)。
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 50005;
const int INF = 0x3f3f3f3f;
int tree[N];
int lowbit(int x)
{
return x&(-x);
}
void add(int i, int val)
{
while(i<N)
{
tree[i] += val;
i+=lowbit(i);
}
}
int sum(int i)
{
int num = 0;
while(i>0)
{
num += tree[i];
i-=lowbit(i);
}
return num;
}
int main()
{
// freopen("in.txt", "r", stdin);
int t, n, num, x, y, Case = 1;
char s[6];
scanf("%d", &t);
while(t--)
{
memset(tree, 0, sizeof(tree));
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%d", &num);
add(i, num);
}
printf("Case %d:\n", Case++);
while(scanf("%s", s))
{
if(s[0]=='E') break;
scanf("%d%d", &x, &y);
if(s[0]=='A') add(x, y);
else if(s[0]=='S') add(x, -y);
else if(s[0]=='Q')
{
printf("%d\n", sum(y)-sum(x-1));
}
}
}
return 0;
}
线段树做法:
思路:单点更新分为三步,建树、更新、求和,详解图看这里点击打开链接;
最简单的线段树,主要是为了熟悉线段树。
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <math.h>
using namespace std;
typedef long long ll;
const int N = 50005;
struct line
{
int l, r;
int val;
}tree[N*4];
int a[N];
void build(int i, int l, int r)
{
tree[i].l = l;
tree[i].r = r;
if(tree[i].l == tree[i].r)//到了子节点
{
tree[i].val = a[l];//注意a数组这里下标不是i
return;//别忘了返回。。
}
int mid = (tree[i].l+tree[i].r)>>1;
build(i*2, l, mid);
build(i*2+1, mid+1, r);
tree[i].val = tree[i*2].val+tree[i*2+1].val;//值在叶子更新完后同步更新
}
void update(int i, int pos, int add)//单点更新
{
if(tree[i].l==tree[i].r && tree[i].l==pos)
{
tree[i].val+=add;
return;
}
int mid = (tree[i].l+tree[i].r)>>1;
if(mid >= pos) update(i*2, pos, add);
else update(i*2+1, pos, add);
tree[i].val = tree[i*2].val+tree[i*2+1].val;
}
int query(int i, int l, int r)
{
if(tree[i].l==l && tree[i].r==r)
{
return tree[i].val;
}
int mid = (tree[i].l+tree[i].r)>>1;
if(mid >= r) return query(i*2, l, r);
else if(mid < l) return query(i*2+1, l, r);
else return query(i*2, l, mid)+query(i*2+1, mid+1, r);
}
int main()
{
// freopen("in.txt", "r", stdin);
int t, n, x, y, Case = 1;
char s[10];
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
printf("Case %d:\n", Case++);
build(1, 1, n);
while(1)
{
scanf("%s", s);
if(s[0] == 'E') break;
scanf("%d%d", &x, &y);
if(s[0] == 'A') update(1, x, y);
else if(s[0] == 'S') update(1, x, -y);
if(s[0] == 'Q')
{
int ans = 0;
ans = query(1, x, y);
printf("%d\n", ans);
}
}
}
return 0;
}