hdu 1166 敌兵布阵
中文题,不发题意。
以前对于一个数组,求某一区间的和,可以用前缀和很快的解决。但是如果这个数组的元素是随时变化的,那么前缀和就不能用了。我们可以用线段树来解决。
线段树是一颗二叉树,每个节点都是一个线段或者说一个区间。根节点是最大的那个线段,每个节点的左右儿子都是自己这条线段的左右两半,直到不能再分,就是叶子结点。
每当我们改变一个点的值,我们从根节点开始向下找,所有包含这一点的线段都作出相应的调整。查找的时候就从根节点开始,直到找到匹配的线段。
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
using namespace std;
const int maxn=50010;
int T,N,a[maxn],i,j;
struct xx
{
int l,r,n;
}x[4*maxn];
void build(int i,int j,int k)
{
x[k].l=i;
x[k].r=j;
x[k].n=0;
if(j>i)
{
int mid=(i+j)>>1;
build(i,mid,2*k);
build(mid+1,j,2*k+1);
}
}
void insert(int k,int A)
{
int i=x[k].l,j=x[k].r;
if(A<=j&&A>=i)
x[k].n+=a[A];
if(i<j)
{
int mid=(i+j)>>1;
if(mid>=A) insert(2*k,A);
else insert(2*k+1,A);
}
}
int find(int i,int j,int k)
{
if(i==x[k].l&&j==x[k].r)
return x[k].n;
if(x[k].l<x[k].r)
{
int mid=(x[k].l+x[k].r)>>1;
if(j<=mid) return find(i,j,2*k);
else if(i>mid) return find(i,j,2*k+1);
else return find(i,mid,2*k)+find(mid+1,j,2*k+1);
}
}
int main()
{
// freopen("data.in","r",stdin);
int t=1;
char s[100];
scanf("%d",&T);
while(T--)
{
scanf("%d",&N);
build(1,N,1);
for(i=1;i<=N;++i)
{
scanf("%d",&a[i]);
insert(1,i);
}
printf("Case %d:\n",t++);
while(scanf("%s",s),strcmp(s,"End"))
{
int i,j;
scanf("%d%d",&i,&j);
if(!strcmp(s,"Add"))
{
a[i]=j;
insert(1,i);
}
else if(!strcmp(s,"Sub"))
{
a[i]=-1*j;
insert(1,i);
}
else if(!strcmp(s,"Query"))
{
printf("%d\n",find(i,j,1));
}
}
}
return 0;
}