HDU 1166 敌兵布阵 树状数组||线段树
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; }
新 blog : www.hrwhisper.me