难得的一道汉语题。
题意就不说。好多人看完题后肯定想的使用一个足够大的数组来模拟,但是这样模拟的话肯定会超时。
二重循环的时间复杂度为O(n^2)。
这个题属于线段树中的对单一结点操作的简单线段树,就是每次update只是对一个点操作。
要注意的是由于线段树的题目一般数据量都比较大,在输入的时候用cin不合适,时间卡的紧的话会超时,所以这块用scanf
还有一点要注意的是乘法除法运算在计算机中的操作也是比较复杂,这里用位运算来实现,防超时。
/*用静态数组来模拟满二叉树*/
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
typedef struct/*树的节点信息*/
{
int l,r,value,add;
} node;
const int Maxsize = 50050;
node tree[Maxsize*4];/*结点一般开这么大,保证空间足够*/
int ans,data[Maxsize];
int main()
{
void build(int v,int l,int r);
void update(int v,int k,int m);
void query(int v,int l,int r);
int ncase,m,n,k;
int kkk = 0;
char str[50];
scanf("%d",&ncase);
while(ncase--)
{
bool flag = false;
scanf("%d",&k);
memset(data,0,sizeof(data));
for(int i = 1 ; i <= k ; i++)
{
scanf("%d",&data[i]);
}
build(1,1,k);
while(scanf("%s",str) && strcmp(str,"End") != 0)
{
scanf("%d %d",&n,&m);
if(str[0] == 'Q')
{
ans = 0;
query(1,n,m);
if(!flag)
{
flag = true;
printf("Case %d:\n",++kkk);
}
printf("%d\n",ans);
}
else if(str[0] == 'A')
{
update(1,n,m);
}
else if(str[0] == 'S')
{
update(1,n,-m);
}
}
}
return 0;
}
void build(int v,int l,int r)/*建立线段树*/
{
tree[v].l = l;
tree[v].r = r;
if(l == r)
{
tree[v].value = data[r];
return;
}
int mid = (l+r)/2;
build(v<<1,l,mid);
build(v<<1|1,mid+1,r);
tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
}
void update(int v,int k,int m)/*更新操作*/
{
if(tree[v].r == tree[v].l && tree[v].l == k)
{
tree[v].value+= m;
return;
}
int mid = (tree[v].l + tree[v].r)>>1;
if(k <= mid)
{
update(v<<1,k,m);
}
else
{
update(v<<1|1,k,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)
{
ans+=tree[v].value;
return;
}
int mid = (tree[v].r+tree[v].l)>>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);
}
}
}