题意要求支持三个操作。
Add(i,j); //点i处增加j
Sub(i,j); //点i处减少j
Query(i,j); //查询区间[i,j]的和
1、树状数组
#include <stdio.h>
#include <string.h>
typedef int LL;
const int MAXN = 50000 + 10;
int C[MAXN], n;
int lowbit(int x) {return (x&-x);}
void add(int i, int d) {for(; i <= n; i += lowbit(i)) C[i] += d;}
LL query(int i) {LL ret = 0; for(; i > 0; i -= lowbit(i)) ret += C[i]; return ret;}
int main()
{
int T, cas, x, i, j;
char cmd[10];
scanf("%d",&T);
for(cas=1; cas<=T; ++cas) {
scanf("%d",&n);
memset(C, 0, sizeof(int)*(n+1));
for(i=1; i<=n; ++i) {
scanf("%d",&x);
add(i, x);
}
printf("Case %d:\n",cas);
while(1) {
scanf("%s",cmd);
if(cmd[0] == 'E') break;
scanf("%d%d",&i,&j);
if(cmd[0] == 'A') {
add(i, j);
}else if(cmd[0] == 'S') {
add(i, -j);
}else if(cmd[0] == 'Q') {
printf("%d\n",query(j) - query(i-1));
}
}
}
return 0;
}
2、线段树
( update:单点增减 query:区间求和 )
#include <cstdio>
#include <cstring>
using namespace std;
#define LL(x) ((x)<<1)
#define RR(x) ((x)<<1|1)
const int maxn = 55555;
struct point
{
int l, r;
int sum;
int mid(){
return (l+r)>>1;
}
}tree[maxn*4];
int num[maxn];
void build(int rt, int l, int r)
{
tree[rt].l = l;
tree[rt].r = r;
if(tree[rt].l == tree[rt].r) {
tree[rt].sum = num[l];
return;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
build(LL(rt), l, mid);
build(RR(rt), mid+1, r);
tree[rt].sum = tree[LL(rt)].sum + tree[RR(rt)].sum;
}
void update(int rt, int pos, int val)
{
if(tree[rt].l == tree[rt].r) {
tree[rt].sum +=val;
return;
}
int mid = (tree[rt].l+tree[rt].r)>>1;
if(pos<=mid) update(LL(rt), pos, val);
else update(RR(rt), pos, val);
tree[rt].sum = tree[LL(rt)].sum + tree[RR(rt)].sum;
}
int query(int rt, int l, int r)
{
if(l <= tree[rt].l && r >= tree[rt].r)
return tree[rt].sum;
int mid = (tree[rt].l + tree[rt].r) >> 1;
int ret = 0;
if(l <= mid) ret += query(LL(rt), l, r);
if( r > mid) ret += query(RR(rt), l, r);
return ret;
}<span style="font-family: 'Courier New', Courier; white-space: pre-wrap;">/*如果恰好题中要求解的区间在左儿子或者右儿子中,那么直接返回其所在的节点的值,否则把左儿子和右儿子中的区间加起来返回*/</span>
int main()
{
int T, n, i, a, b, val;
char str[10];
scanf("%d",&T);
for(int cas = 1; cas<=T; ++cas) {
scanf("%d",&n);
for(i=1; i<=n; ++i) scanf("%d",&num[i]);
build(1,1,n);
printf("Case %d:\n", cas);
while(1)
{
scanf("%s",str);
if(str[0]=='E') break;
if(str[0]=='Q'){
scanf("%d%d",&a,&b);
printf("%d\n",query(1,a,b));
}
else if(str[0]=='A') {
scanf("%d%d",&a,&val);
update(1,a,val);
}
else if(str[0]=='S') {
scanf("%d%d",&a,&val);
update(1,a,-val);
}
}
}
}
线段树(update: 2014.07.15)
#include <stdio.h>
#include <string.h>
const int maxn = 50000 + 5;
int SUM[maxn<<4];
int num[maxn];
void PushUp(int rt)
{
SUM[rt] = SUM[rt<<1] + SUM[rt<<1|1];
}
void build(int rt, int l, int r)
{
if(l == r)
{
SUM[rt] = num[l];
return ;
}
int m = (l+r)>>1;
build(rt<<1, l, m);
build(rt<<1|1, m+1, r);
PushUp(rt);
}
void update(int rt, int l, int r, int p, int v)
{
if(l == r)
{
SUM[rt] += v;
return ;
}
int m = (l+r)>>1;
if(p<=m) update(rt<<1, l, m, p, v);
if(p>m) update(rt<<1|1, m+1, r, p, v);
PushUp(rt);
}
int query(int rt, int l, int r, int L, int R)
{
if(L<=l && r<=R)
{
return SUM[rt];
}
int m = (l+r)>>1;
int ret = 0;
if(L<=m) ret += query(rt<<1, l, m, L, R);
if(R>m) ret += query(rt<<1|1, m+1, r, L, R);
return ret;
}
int main()
{
int t, i, n, a, b;
scanf("%d", &t);
for(int cas=1; cas<=t; ++cas)
{
printf("Case %d:\n", cas);
scanf("%d", &n);
for(i=1; i<=n; ++i) scanf("%d", &num[i]);
build(1, 1, n);
char cmd[10];
while(scanf("%s", cmd))
{
if(cmd[0]=='E') break;
scanf("%d%d", &a, &b);
if(cmd[0] == 'Q')
{
int ret = query(1, 1, n, a, b);
printf("%d\n", ret);
}
else if(cmd[0] =='S')
{
update(1, 1, n, a, -b);
}
else if(cmd[0]=='A')
{
update(1, 1, n, a, b);
}
}
}
return 0;
}