您的位置:首页 > 其它

hdu 1166 敌兵布阵(线段树-单点更新)

2013-07-26 10:16 148 查看
题意:有N个兵营,每个兵营都给出了人数ai(下标从1开始),有四种命令,(1)”Addij",表示第i个营地增加j人。(2)“Sub i j”,表示第i个营地减少j人。(3)“Query ij",查询第i个营地到第j个营地的总人数。(4)”End“,表示命令结束。

有三种操作:询问区间总和,增加某个兵营的兵的数目,减少某个兵营的兵的数目。实际上也只有两个。

在更新的时候,每到一个区间就把当前区间的sum增加对应的数目,到达叶子结点是返回。这样就可以不会回溯去更新父亲结点的值。查询的时候,如果区间完全匹配,直接返回区间的sum值,否则向下寻找,直到完全匹配,然后返回它们的和就可以。这时候,结果里保存的边界是它们真正的边界。
// Time 203ms; Memory 1944K
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 1<<17

using namespace std;

int size,n,sum,all[40010];
struct line
{
int l,r;
int n;
}a[maxn];

void init()
{
int i;
for(n=1;n<size;n<<=1);
for(i=n;i<2*n;i++)
{
a[i].l=a[i].r=i-n+1;
a[i].n=0;
}
for(i=n-1;i>0;i--)
{
a[i].l=a[2*i].l;
a[i].r=a[2*i+1].r;
a[i].n=0;
}
}
void insert(int i,int x,int m)
{
if(x>=a[i].l && x<=a[i].r) a[i].n+=m;
if(a[i].l==a[i].r) return;
int mid=(a[i].l+a[i].r)/2;
if(x>mid) insert(2*i+1,x,m);
else insert(2*i,x,m);
}
void find(int x,int y,int i)
{
if(x==a[i].l && y==a[i].r)
{
sum+=a[i].n;
return;
}
if(a[i].l==a[i].r) return;
int mid=(a[i].l+a[i].r)/2;
if(x>mid) find(x,y,2*i+1);
else if(y<=mid) find(x,y,2*i);
else
{
find(x,mid,2*i);
find(mid+1,y,2*i+1);
}
}
int main()
{
int i,j,k,t,x,y,m;
char s[7];
scanf("%d",&t);
for(i=0;i<t;i++)
{
scanf("%d",&size);
init();
for(j=0;j<size;j++)
{
scanf("%d",&k);
insert(1,j+1,k);
}
k=0;
while(scanf("%s",s)!=EOF && strcmp(s,"End"))
{
if(strcmp(s,"Add")==0)
{
scanf("%d%d",&x,&m);
insert(1,x,m);
}
else if(strcmp(s,"Sub")==0)
{
scanf("%d%d",&x,&m);
insert(1,x,-m);
}
else
{
scanf("%d%d",&x,&y);
sum=0;
find(x,y,1);
all[k++]=sum;
}
}
printf("Case %d:\n",i+1);
for(j=0;j<k;j++) printf("%d\n",all[j]);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM-ICPC C hdu 线段树