传送门:点击打开链接
题意:N个数, 有两种操作,单点修改跟区间求和
分析:
线段树裸题,也是树状数组裸题。
手敲了一个线段树模板,已经非常精简了,希望看到的同学喜欢。
代码如下:
#include <cstdio>
using namespace std;
const int maxn = 50000+5;
int a[maxn];
int n;
struct node{
int left,right;
int sum;
};
struct Tree{
node tr[maxn*4];
#define lch(u) (u<<1)
#define rch(u) (u<<1|1)
#define Mid (tr[u].left+tr[u].right)>>1
inline void push_up(int u) {
tr[u].sum = tr[lch(u)].sum + tr[rch(u)].sum;
}
void build(int u,int l, int r){
tr[u].left = l; tr[u].right = r;
if (l == r) {
tr[u].sum = a[l];
return ;
}
int mid = Mid;
build(lch(u),l,mid);
build(rch(u),mid+1,r);
push_up(u);
}
void add(int u, int pos, int val){
tr[u].sum += val;
if (tr[u].left == tr[u].right) return;
int mid = Mid;
if (pos<=mid) add(lch(u),pos,val);
else add(rch(u),pos,val);
}
int query(int u, int l, int r){
if (l<=tr[u].left && tr[u].right<=r) return tr[u].sum;
int mid = Mid;
int ans = 0;
if (r<=mid) ans += query(lch(u),l,r);
else if (l>mid) ans += query(rch(u),l,r);
else {
ans += query(lch(u),l,r);
ans += query(rch(u),l,r);
}
return ans;
}
}T;
int main(){
int t;
scanf("%d",&t);
int kase = 0;
while (t--){
scanf("%d",&n);
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
T.build(1,1,n);
printf("Case %d:\n",++kase);
char str[10];
int x,y;
while (scanf("%s",str)==1){
if (str[0]=='E') break;
scanf("%d %d",&x,&y);
if (str[0]=='A') T.add(1,x,y);
else if (str[0]=='S') T.add(1,x,-y);
else {
printf("%d\n",T.query(1,x,y));
}
}
}
return 0;
}
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 50000+10;
int n;
int c[maxn];
int x,y;
inline int lowbit(int x) { return x&(-x); }
void add(int x, int val){
while (x<=n) {
c[x] += val;
x += lowbit(x);
}
}
int sum(int x){
int ans = 0;
while (x) {
ans += c[x];
x -= lowbit(x);
}
return ans;
}
int main(){
int T;
scanf("%d",&T);
int kase = 0;
while (T--){
scanf("%d",&n);
memset(c,0,sizeof(c));
for (int i=1; i<=n; i++) {
scanf("%d",&x);
add(i,x);
}
printf("Case %d:\n",++kase);
char str[10];
while (scanf("%s",str)==1) {
if (str[0]=='E') break;
scanf("%d %d",&x,&y);
if (str[0]=='A') add(x,y);
else if (str[0]=='S') add(x,-y);
else printf("%d\n",sum(y)-sum(x-1));
}
}
return 0;
}
总结:如果在线段树和树状数组两者皆可的情况下使用树状数组会简单很多,代码复杂度比较低。
对于这题,二者的时间复杂度并无区别,实际运行线段树更优秀一些。