HDU 1166 敌兵布阵 树状数组||线段树

时间:2021-08-14 13:13:28

http://acm.hdu.edu.cn/showproblem.php?pid=1166

题目大意:

给定n个数的区间N<=50000,还有Q个询问(Q<=40000)求区间和。

每个询问可能增加点k     x的值或者减少x。

思路:

原题描述很有爱啊~

树状数组好久没写了~

依旧很熟练,WA了两三次,第一次因为没有输出case,。。。。。。。第二次发现多组数据没有初始化。T^T

~像这种单点修改求区间和的还是用树状数组比较简单~

树状数组:

#include<cstdio>
#include<cstring>
const int MAXN=50000+10;
int sum[MAXN];
inline int lowbit(int x)
{
return x&-x;
} int getsum(int x)
{
int ans=0;
while(x>0)
{
ans+=sum[x];
x-=lowbit(x);
}
return ans;
} void add(int x,int v)
{
while(x<MAXN)
{
sum[x]+=v;
x+=lowbit(x);
}
} int main()
{
//freopen("e:\\input.txt","r",stdin);
int T,kase=1;
scanf("%d",&T);
while(T--)
{
memset(sum,0,sizeof(sum));
int n,t;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d",&t);
add(i,t);
}
char cmd[10];
printf("Case %d:\n",kase++);
while(scanf("%s",cmd),cmd[0]!='E')
{
int a,b;
scanf("%d%d",&a,&b);
if(cmd[0]=='Q')
printf("%d\n",getsum(b)-getsum(a-1));
else if(cmd[0]=='S')
add(a,-b);
else
add(a,b);
}
}
return 0;
}

线段树:

#include<cstdio>
#include<cstring>
const int MAXN=50000+10;
int sum[MAXN<<2],a[MAXN];
void build(int k,int L,int R)
{
if(L==R) sum[k]=a[L];
else
{
int m=(L+R)/2;
build(k*2,L,m);
build(k*2+1,m+1,R);
sum[k]= sum[k*2]+sum[k*2+1];
}
} int getsum(int k,int L,int R,int a,int b)
{
int m=(L+R)/2,ans=0;
if(a<=L && R<=b) return sum[k];
if(a<=m) ans+=getsum(k*2,L,m,a,b);
if(m<b) ans+=getsum(k*2+1,m+1,R,a,b);
return ans;
} void update(int k,int L,int R,int x,int v)
{
if(L==R) sum[k]+=v;
else
{
int m=(L+R)/2;
if(x<=m) update(k*2,L,m,x,v);
else update(k*2+1,m+1,R,x,v);
sum[k]+=v;
} } int main()
{
// freopen("e:\\input.txt","r",stdin);
int T,kase=1;
scanf("%d",&T);
while(T--)
{
memset(sum,0,sizeof(sum));
int n,t;
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]); build(1,1,n);
char cmd[10];
printf("Case %d:\n",kase++);
while(scanf("%s",cmd),cmd[0]!='E')
{
int a,b;
scanf("%d%d",&a,&b);
if(cmd[0]=='Q')
printf("%d\n",getsum(1,1,n,a,b));
else if(cmd[0]=='S')
update(1,1,n,a,-b);
else
update(1,1,n,a,b);
}
}
return 0;
}