题目地址:点击打开链接
思路:不要用cin,cout,输入输出,会超时,update(),单点增减,query()区间求和,前2个代码是为了便于理解,写的时候看第三个代码,特别简洁
AC代码:
#include <iostream>
#include <cstdio>
using namespace std;
int n,sum;
int a[50010];
struct node
{
int l;
int r;
int value;
}tree[500000];//开数据量的4倍左右
void bulid(int v,int l,int r)
{
tree[v].l = l;
tree[v].r = r;
if(l == r)
{
tree[v].value = a[l];
return;
}
int mid = (l + r) / 2;
bulid(v*2,l,mid);
bulid(v*2+1,mid+1,r);
tree[v].value = tree[v*2].value + tree[v*2+1].value;
}
void update(int v,int l,int r,int m)
{
if(tree[v].l == l && tree[v].r == r)
{
tree[v].value += m;
return;
}
int mid = (tree[v].l + tree[v].r) / 2;
if(r <= mid)//到目前节点的左节点去找要找的区间
update(v*2,l,r,m);
else
update(v*2+1,l,r,m);//到目前节点的右节点去找要找的区间
tree[v].value = tree[v*2].value + tree[v*2+1].value;//往上传增量
}
void query(int v,int l,int r)
{
if(tree[v].l == l && tree[v].r == r)
{
sum += tree[v].value;
return;
}
int mid = (tree[v].l + tree[v].r) / 2;
if(r <= mid)
query(v*2,l,r);//只跨一个区间,到目前节点的左节点去查询
else if(l > mid)
query(v*2+1,l,r);//只跨一个区间,到目前节点的右节点去查询
else//横跨二个区间,左右节点都得查询
{
query(v*2,l,mid);
query(v*2+1,mid+1,r);
}
}
int main()
{
char s[10];
int t,x,y,i,l = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
{
cin>>a[i];
}//在update()函数输入也可,不用设a这个数组
bulid(1,1,n);
printf("Case %d:\n",l++);
while(scanf("%s",s) && s[0] != 'E')
{
scanf("%d%d",&x,&y);
if(s[0] == 'Q')
{
sum = 0;
query(1,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点
printf("%d\n",sum);
}
else if(s[0] == 'A')
update(1,x,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点,第四个参数是增量
else if(s[0] == 'S')
update(1,x,x,-y);
}
}
return 0;
}
AC代码2:(用了位运算,应该快一点)
#include <iostream>
#include <cstdio>
using namespace std;
int n,sum;
int a[50010];
struct node
{
int l;
int r;
int value;
}tree[500000];//开数据量的4倍左右
void bulid(int v,int l,int r)
{
tree[v].l = l;
tree[v].r = r;
if(l == r)
{
tree[v].value = a[l];
return;
}
int mid = (l + r) >> 1;
bulid(v<<1,l,mid);
bulid(v<<1|1,mid+1,r);
tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
}
void update(int v,int l,int r,int m)
{
if(tree[v].l == l && tree[v].r == r)
{
tree[v].value += m;
return;
}
int mid = (tree[v].l + tree[v].r) >> 1;
if(r <= mid)//到目前节点的左节点去找要找的区间
update(v<<1,l,r,m);
else
update(v<<1|1,l,r,m);//到目前节点的右节点去找要找的区间
tree[v].value = tree[v<<1].value + tree[v<<1|1].value;//往上传增量
}
void query(int v,int l,int r)
{
if(tree[v].l == l && tree[v].r == r)
{
sum += tree[v].value;
return;
}
int mid = (tree[v].l + tree[v].r) >> 1;
if(r <= mid)
query(v<<1,l,r);//只跨一个区间,到目前节点的左节点去查询
else if(l > mid)
query(v<<1|1,l,r);//只跨一个区间,到目前节点的右节点去查询
else//横跨二个区间,左右节点都得查询
{
query(v<<1,l,mid);
query(v<<1|1,mid+1,r);
}
}
int main()
{
char s[10];
int t,x,y,i,l = 1;
scanf("%d",&t);
while(t--)
{
scanf("%d",&n);
for(i=1; i<=n; i++)
{
cin>>a[i];
}//在update()函数输入也可,不用设a这个数组
bulid(1,1,n);
printf("Case %d:\n",l++);
while(scanf("%s",s) && s[0] != 'E')
{
scanf("%d%d",&x,&y);
if(s[0] == 'Q')
{
sum = 0;
query(1,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点
printf("%d\n",sum);
}
else if(s[0] == 'A')
update(1,x,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点,第四个参数是增量
else if(s[0] == 'S')
update(1,x,x,-y);
}
}
return 0;
}
AC代码3:(上面代码风格太丑了,参考大神的代码写的)
大神地址:http://blog.csdn.net/metalseed/article/details/8039326
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>
const int inf = 0x3f3f3f3f;//1061109567
typedef long long LL;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
using namespace std;
int sum[maxn<<2];
char a[10];
void pushup(int rt)
{
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
if(l == r)
{
scanf("%d",&sum[rt]);
return;
}
int m = (l+r)>>1;
build(lson);
build(rson);
pushup(rt);
}
void update(int c,int op,int l,int r,int rt)
{
if(l == r)
{
sum[rt] += op;
return;
}
int m = (l+r)>>1;
if(c <= m) update(c,op,lson);
else update(c,op,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(l>=L && r<=R) return sum[rt];
int m = (l+r)>>1;
int ans = 0;
if(L <= m) ans += query(L,R,lson);
if(R > m) ans += query(L,R,rson);
return ans;
}
int main()
{
int t,n,cas=1;
scanf("%d",&t);
while(t--)
{
int c,d;
printf("Case %d:\n",cas++);
scanf("%d",&n);
build(1,n,1);
while(scanf("%s",a) && a[0] != 'E')
{
scanf("%d%d",&c,&d);
if(a[0] == 'Q') printf("%d\n",query(c,d,1,n,1));
else if(a[0] == 'A') update(c,d,1,n,1);
else if(a[0] == 'S') update(c,-d,1,n,1);
}
}
return 0;
}
AC代码4:
#include<stdio.h>
#include<string.h>
int a[50010];
char sh[15];
int n;
int lowbit(int x)
{
return x&(-x);
}
void update(int pos,int num)
{
while(pos<=n)
{
a[pos] += num;
pos += lowbit(pos);//把他的父节点也改了
}
}
int sum(int end)//求1到end的值
{
int sum = 0;
while(end>0)
{
sum += a[end];
end -= lowbit(end);//1-end由多段值组成,分别求多段的值
}
return sum;
}
int main()
{
int t,i,x,y,l = 1,sum1;
scanf("%d",&t);
while(t--)
{
memset(a,0,sizeof(a));
scanf("%d",&n);
for(i=1; i<=n; i++)
{
scanf("%d",&x);
update(i,x);
}
printf("Case %d:\n",l++);
while(scanf("%s",sh))
{
if(sh[0] == 'Q')
{
scanf("%d%d",&x,&y);
sum1 = sum(y) - sum(x-1);
printf("%d\n",sum1);
}
else if(sh[0] =='A')
{
scanf("%d%d",&x,&y);
update(x,y);
}
else if(sh[0] == 'S')
{
scanf("%d%d",&x,&y);
update(x,-y);
}
else if(sh[0] == 'E')
break;
}
}
return 0;
}