为了解决自己一直烦恼的数据结构的短板,今天开始从线段树入手……这也是发表的第一篇博客。
这个题是最基本的入门线段树,sum数组里存的是一个区间内敌军的数量,push_up是根据子节点的情况更新父节点的值
线段树可以看成是完全二叉树(可能有些节点下没了子节点破坏了整体的结构,但是在数组的处理时,还是可以当做完全二叉树,因此rt的左儿子就是rt<<1右儿子就是(rt<<1)+1)这么做比存一个结构体然后记录左右儿子的下标要节省空间……是看了notonlysuccess的线段树完整版之后才知道能这么办的,膜拜一下大神
#include <cstdio>
#include <cstring>
#define FF(i,n) for(int i=0; i<n; i++)
const int MAX = 50010;
int sum[MAX<<2];
void push_up(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;
}
build(l,(l+r)>>1,rt<<1);
build(((l+r)>>1)+1,r,(rt<<1)+1);
push_up(rt);
}
void update(int p,int add,int l,int r,int rt)
{
if(l==r)
{
sum[rt]+=add;
return;
}
int mid = (l+r)>>1;
if(p<=mid) update(p,add,l,mid,rt<<1);
else update(p,add,mid+1,r,(rt<<1)+1);
push_up(rt);
}
int query(int L,int R,int l,int r,int rt)
{
if(L<=l&&R>=r) return sum[rt];
int mid = (l+r)>>1;
int ans = 0;
if(L<=mid) ans+=query(L,R,l,mid,rt<<1);
if(R>mid) ans+=query(L,R,mid+1,r,(rt<<1)+1);
return ans;
}
int main()
{
int cas;
scanf("%d",&cas);
int cnt = 0;
while(cas--)
{
int n;
scanf("%d",&n);
build(1,n,1);
printf("Case %d:\n",++cnt);
char s[10];
while(scanf("%s",s)&&s[0]!='E')
{
int i,j;
scanf("%d%d",&i,&j);
if(s[0]=='Q')
printf("%d\n",query(i,j,1,n,1));
else if(s[0]=='A')
update(i,j,1,n,1);
else if(s[0]=='S')
update(i,-j,1,n,1);
}
}
return 0;
}