今天新学了一个知识,叫做线状数组,主要应用领域
1,数据频繁更新
2,求解某一段区间的和
以上产景情况下可以使用线状数组,更新某一个数据和求某一段时间之和时间复杂度都是Log(N) {常规情况是O(1)和O(N)}
线状数组和RMQ差不多,都可以再Log(N)时间复杂度内求解某一段区间的长度,线状数组额实现方式更为简单,更为方便
以下可以当做线段树的模板
主要函数有lowbit给定制定数字二进制下在末尾为0的个数。
Update更新某一节点的值。
getsum求解某一区间的值
Update是从叶子到根顶部跟新,getsum是从上至下更新,父子节点的差距就是lowbit(n);
求解一段区间的和为什么可以用来求解中位数呢?
声明数组,初始化为0,当某个数出现的时候,比如10,那么tree[10]=1; 比如查找1-100就可以知道100以内有多少个数据存在了。
有一个问题比如
1 2 3 4 5 6 7 8 9 10
0 0 0 1 0 0 1 0 1 0
那么求解1-4的和为1
求解1-5也为1,求解1-6也为1.那么我怎么知道是哪一个作为?
(编码的时候只有当l==r时候才返回值,也就是区间左右都相等的时候才返回值,否则不返回值,如果是getsum(mid)==mid不做特殊处理。最初写成返回return mid
还是树状数组理解不够深。。待续。。。
)
// 1057.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<string>
#include<stack>
using namespace std;
#define MAX 100010
stack<int> s;
int tree[MAX]={0};
int lowbit(int ind)
{
return ind & -ind;
}
void update(int ind,int val)
{
while(ind<=MAX)
{
tree[ind]+=val;
ind+=lowbit(ind);
}
}
int getsum(int ind)
{
int sum=0;
while(ind>0) //not >=0
{
sum+=tree[ind];
ind-=lowbit(ind);
}
return sum;
}
int findmid(int number,int l,int r)
{
if(l==r)
return l;
int mid=(l+r)/2;
int sum=getsum(mid);
if(sum<number)
{
return findmid(number,mid+1,r);
}
else
{
return findmid(number,l,mid);
}
/*
最后return mid会出错
*/
}
int main()
{
int num;
string op;
char op_name[15];
int tmp;
freopen("1057.txt","r",stdin);
while(scanf("%d",&num)!=EOF)
{
for(int i=0;i<num;i++)
{
scanf("%s",op_name);
op=string(op_name);
if(op=="Pop")
{
if(!s.empty())
{
tmp=s.top();
update(tmp,-1);
printf("%d\n",tmp);
s.pop();
}
else
{
printf("Invalid\n");
}
}
if(op=="Push")
{
scanf("%d",&tmp);
s.push(tmp);
update(tmp,1);
}
if(op=="PeekMedian")
{
int size=s.size();
if(size==0)
{
printf("Invalid\n");
continue;
}
if(size%2==0)
size=size/2;
else
size=(size+1)/2;
int mid=findmid(size,1,MAX);
printf("%d\n",mid);
}
}
}
return 0;
}