HDU-#1166 敌兵布阵 (树状数组&线段树)
2014-07-12 13:53
399 查看
题目大意:动态连续和查询问题,标准的树状数组的题哈。
解题思路:直接按照树状数组模板就可AC。但是用树状数组写的,线段树均可以写。二者不可逆,详见code。不过线段树很强大很实用的一种算法,你值得拥有。
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1166
BIT code:
线段树是很强大的一种算法,可以做多种算法的事,当然可以替换树状数组的所有事,特别是卡时间的时候,线段树的优势一下就体现出来了。写出来和理解起来虽然没有BIT易懂,但确实很高效,很值得学习的。线段树有两种写法,一是递归的,一是非递归的。前者容易懂,但后者更高效。下面给出两种写法的code,详见注释。
递归code:
非递归code:
书上说这种写法更快些,写不出来,在网上找了下,的确要高大上一些,弄了一会没弄懂,书上也写着递归的写法一般就足够了,这种用的很少,就没深究下去了。直接copy过来了,感兴趣可以看一下。拿到OJ 测试了下,没发现时间快了,不过内存倒大了些。不过还是膜拜下大神些。。。
解题思路:直接按照树状数组模板就可AC。但是用树状数组写的,线段树均可以写。二者不可逆,详见code。不过线段树很强大很实用的一种算法,你值得拥有。
题目来源:http://acm.hdu.edu.cn/showproblem.php?pid=1166
BIT code:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 50000+10; int arr[MAXN],t,val,ai,n,l,r,k; char opr[10]; int lowbit(int i){return i&(-i);} void add(int i,int val){//add操作 while(i<=n){ arr[i]+=val; i+=lowbit(i); } } int sum(int i){//sum操作 int ans=0; while(i>0){ ans+=arr[i]; i-=lowbit(i); } return ans; } int main() { k=0; scanf("%d",&t); while(t--){ memset(arr,0,sizeof(arr)); scanf("%d",&n); for(int i=1;i<=n;i++){ //将已有的值进行存入 scanf("%d",&val); add(i,val); } printf("Case %d:\n",++k); while(scanf("%s",&opr) && opr[0]!='E'){ //接收操作,只要不是End就执行 scanf("%d%d",&ai,&val); if(opr[0]=='A') add(ai,val); else if(opr[0]=='S') //减值等于加负 add(ai,-val); else printf("%d\n",sum(val)-sum(ai-1));//求区间和的操作,类似前缀和 } } return 0; }
线段树是很强大的一种算法,可以做多种算法的事,当然可以替换树状数组的所有事,特别是卡时间的时候,线段树的优势一下就体现出来了。写出来和理解起来虽然没有BIT易懂,但确实很高效,很值得学习的。线段树有两种写法,一是递归的,一是非递归的。前者容易懂,但后者更高效。下面给出两种写法的code,详见注释。
递归code:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int MAXN = 50000+10; int st[MAXN*4]; int t,k,n,x,y,ans; char opr[10]; void Bulid(int o,int l,int r){ //建树:自底向上递归实现 if(l==r) scanf("%d",st+o); //接收各结点值 else{ int m=(l+r)/2; Bulid(o*2,l,m); Bulid(o*2+1,m+1,r); st[o]=st[o*2]+st[o*2+1];//本结点值为左右节点之和 } } void updata(int o,int l,int r,int x,int v){ if(l==r) st[o]+=v; //叶结点,直接更新值 else{ int m=(l+r)/2; if(x<=m) updata(o*2,l,m,x,v); //先递归更新左子树 else updata(o*2+1,m+1,r,x,v);//或者右子树 st[o]=st[o*2]+st[o*2+1]; //然后计算本节点的值 } } void query(int o,int l,int r,int x,int y){ if(x<=l && y>=r) ans+=st[o]; //当前结点完全包含在查询区间内,则直接为结点值 else{ int m=(l+r)/2; if(x<=m) query(o*2,l,m,x,y); //向左查询 if(y>m) query(o*2+1,m+1,r,x,y); //向右查询 } } int main(){ k=1;scanf("%d",&t); while(t--){ scanf("%d",&n); Bulid(1,1,n); //建树 printf("Case %d:\n",k++); while(scanf("%s",opr),opr[0]!='E'){ scanf("%d%d",&x,&y); if(opr[0]=='Q'){ ans = 0; query(1,1,n,x,y); printf("%d\n",ans); } else{ if(opr[0]=='S') y*=-1; updata(1,1,n,x,y); } } } return 0; }
非递归code:
书上说这种写法更快些,写不出来,在网上找了下,的确要高大上一些,弄了一会没弄懂,书上也写着递归的写法一般就足够了,这种用的很少,就没深究下去了。直接copy过来了,感兴趣可以看一下。拿到OJ 测试了下,没发现时间快了,不过内存倒大了些。不过还是膜拜下大神些。。。
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> using namespace std; const int MAXN = 50000+10; int c[4*MAXN],M; void add(int k, int v) { for (c[k+=M]+=v, k>>=1 ; k; k>>=1) if (k<M) c[k]=c[k << 1] + c[k << 1 | 1];//就是c[k]=c[2*k]+c[2*k+1]更快计算的一种写法 return ; } int query(int s, int t) { int Ans=0; for (s=s+M-1,t=t+M+1; s^t^1; s>>=1,t>>=1)//s^t^1表示当s和t值一样的时候执行,否则不执行,^异或的用法 { if (!(s & 1)) Ans+=c[s^1]; if (t & 1) Ans+=c[t^1]; } return Ans; } int main() { int T; scanf("%d",&T); for (int k=1; k<=T; k++) { int n; scanf("%d",&n); M=1 << (int)(log((double)n)/log(2.0)+1);//m=2的(log2(n)+1)次方,推一下就知道。 for (int i=0; i!=n; i++) scanf("%d",&c[i+M]); for (int i=M-1; i>=1; i--) c[i]=c[i << 1]+c[i << 1 | 1];//c[i]=c[2*i]+c[2*i+1] char q[10]; int x,y; printf("Case %d:\n",k); while (scanf("%s",q) && strcmp(q,"End")) { scanf("%d%d",&x,&y); if (q[0]=='A') add(x-1,y); else if (q[0]=='S') add(x-1,-y); else printf("%d\n",query(x-1,y-1)); } } }
相关文章推荐
- HDU 1166-敌兵布阵【树状数组&&线段树单点更新】【模板】
- HDU 1166 敌兵布阵 (线段树 & 树状数组)
- HDU 1166 敌兵布阵(区间求和&(线段树|树状数组))
- hdu 1166 敌兵布阵 <树状数组>
- HDU 1166 敌兵布阵 (树状数组·线段树)
- hdu1166敌兵布阵 树状数组&线段树 单点更新求区间和
- hdu 1166 敌兵布阵【入门线段树 & 树状数组】
- HDU 1166 敌兵布阵 (线段树基础&树状数组基础)
- HDU 1166 敌兵布阵 线段树,单点更新
- HDU 1166 敌兵布阵(树状数组,线段树)
- Hdu-1166 敌兵布阵【线段树(单点更新)】
- HDU 1166敌兵布阵 线段树
- HDU-1166 敌兵布阵 线段树
- hdu 1166 敌兵布阵 基础线段树 2种做法
- hdu 1166 敌兵布阵(线段树——单点更新)
- HDU-1166 敌兵布阵 不完全线段树
- HDU 1166 敌兵布阵(线段树)
- HDU-1166-敌兵布阵(线段树)
- HDU 1166 敌兵布阵【线段树】
- 线段树之(四) hdu 1166敌兵布阵