C - 敌兵布阵
作者:互联网
题目:
题目网址:Problem - 1166 (hdu.edu.cn)
思路:
对N个数据进行单个的增加或者减少,并随时获取一段数据的和;
普通的方法只能让增减和查询其中一个的复杂度为O(n);
这里我就需要用的线段树进行存储让两个步骤的复杂度都为O(log n);
线段树就是用空间来代替时间;
首先要对数据进行初始化构建线段树,在这里我们用数组来存储;
首先从总和为tree数组的开头在以下标node,node*2+1为左孩子,node*2+2为右孩子
以完全二叉树的形式存储数据的和;
构建tree数组的时候利用递归去操作;
代码实现:
#include<iostream> #include<cstring> #include<cstdio> using namespace std; struct { int a,b,sum; }t[140000];//在这里我们用结构体数组,顺便存储左右端点值 int r[50010],summ,k; void buildd(int x,int y,int num)//构造线段树 { t[num].a=x;//存储左右端点值 t[num].b=y; if(x==y) t[num].sum=r[y];//递归出口,当左右相等时就等于只剩下一个点就等于数据本身 else { buildd(x,(x+y)/2,num*2);//取中间值分开成两个区间都进行递归 buildd((x+y)/2+1,y,num*2+1); t[num].sum=t[num*2].sum+t[num*2+1].sum;//递归上到最后就会慢慢向上进行数据相加 } } void query(int x, int y, int num)//查找 { if(x<=t[num].a&&y>=t[num].b)//递归出口递归区间在所给范围内 summ+=t[num].sum; else{ int minn=(t[num].a+t[num].b)/2;//区间中间值 if(x>minn) query(x,y,num*2+1);//如果大于中间值只递归右孩子 else if(y<=minn)//如果小于只递归左孩子 query(x,y,num*2); else //如果没有就都递归 { query(x,y,num*2); query(x,y,num*2+1); } } } void update(int x, int y, int num)//数据的更新 { t[num].sum+=y;//对总和先进行更新 if(t[num].a==x&&t[num].b==x) return ;//递归出口当左右端点相等时 if (x>(t[num].a+t[num].b)/2) update(x,y,num*2+1);//如果区间包括x就进行递归 else update(x,y,num*2); } int main() { int t; int cnt=0; cin>>t; while(t--) { int n,m; char ch[10]; cin>>k; r[0]=0; for(int i=1;i<=k;i++) cin>>r[i];//输入数据先存储在一个数组里 buildd(1,k,1);//在进行线段树构建 printf("Case %d:\n",++cnt); while(cin>>ch) {//对输入操作进行判断,并作出对应操作 if(strcmp(ch,"End")==0) break; else if(strcmp(ch,"Query")==0) { cin>>n>>m; summ=0; query(n,m,1); printf("%d\n",summ); } else if(strcmp(ch,"Add")==0) { cin>>n>>m; update(n,m,1); } else if(strcmp(ch,"Sub")==0) { cin>>n>>m; update(n,-1*m,1); } } } return 0; }
标签:ch,num,递归,int,sum,else,敌兵,布阵 来源: https://www.cnblogs.com/wangdy/p/15098936.html