敌兵布阵(HDOJ1166)
最近一个周在学习线段树,晒晒学习成果。
线段树结构:以最大区间是10为例
1【1 , 10】 / \ 2【1,5】 3【6,10】 / \ / \ 4【1,3】 5【4,5】 6【6,8】 7【9,10】 / \ / \ / \ / \ 8【1,2】9【3,3】10【4,4】11【5,5】 12【6,7】13【8,8】14【9,9】15【10,10】 / \ / \ 16【1,1】17【2,2】 22【6,6】23【7,7】叶子节点记录最原始的数据,其他节点则记录这个区间的数据(或者是这个区间的和,或者是最大值或者是最小值,根据题目而定)。
原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166 (区间求和)
summary(int index)函数用来计算第index个节点所表示的区间内数据的和;
build(int l,int r,int index)函数用来建造线段树,把原始数据填入的同时计算各区间的数据和;
update(int l,int r,int index,int updateindex,int updatedata)更新最原始数据的同时,从线段树下面开始向上更新各区间的结果;
query(int l,int r,int index,int queryL,int queryR)查询该区间的数据和。
下面是源代码:
#include<iostream>
using namespace std;
#define lson l,mid,index<<1
#define rson mid+1,r,index<<1|1
#define max 55555
int num[max<<2];
void summary(int index)
{
num[index]=num[index<<1]+num[index<<1|1];
}
void build(int l,int r,int index)
{
if(l==r)//叶子节点读入数据
{
scanf("%d",&num[index]);
return ;
}
int mid=(l+r)>>1;
build(lson);//构建左孩子
build(rson);//构建右孩子
summary(index);
}
void update(int l,int r,int index,int updateindex,int updatedata)
{
if(l==r)
{
num[index]+=updatedata;
return ;
}
int mid=(l+r)>>1;
if(updateindex<=mid)
update(lson,updateindex,updatedata);
else
update(rson,updateindex,updatedata);
summary(index);
}
int query(int l,int r,int index,int queryL,int queryR)
{
if(queryL<=l&&queryR>=r)
{
return num[index];
}
int sum=0;
int mid=(l+r)>>1;
if(queryL<=mid)//把查询区间分为两段,一段是(queryL,mid),另一段是(mid+1,queryR)
sum+=query(lson,queryL,queryR);
if(queryR>mid)
sum+=query(rson,queryL,queryR);
return sum;
}
int main()
{
int count,a,b,c;
scanf("%d",&count);
char ch[6];
for(int i=1;i<=count;i++)
{
scanf("%d",&a);;
build(1,a,1);
cout<<"Case "<<i<<":"<<endl;
while(scanf("%s",ch))
{
if(ch[0]=='E')break;
scanf("%d %d",&b,&c);
if(ch[0]=='Q')
printf("%d\n",query(1,a,1,b,c));
else if(ch[0]=='A')
update(1,a,1,b,c);
else if(ch[0]=='S')
update(1,a,1,b,-c);
}
}
}

浙公网安备 33010602011771号