标签:实现 增加 补齐 turn amp tree pre span lock
动态区间最值问题(查询、更新)
线段树原理简单,但我看刘书上实现代码比较麻烦,于是试着自己实现了一下。说明如下:
查询:按照线段树的思想,找到待查询区间内完全二叉树的树根,并取最小值即可。复杂度的为\(O(log(n))\)。
查询复杂度的证明:线段树的查询复杂度应当时\(O(log(n))\)。由代码可知,可能会使复杂度增加的仅有while循环。但能够进入while,当且仅当此时的l和r在同一颗子树里。分析可知,下一次进入while的树高小于等于上一次出while的树高,因此while循环最多要花\(O(log(n))\)的时间。
int stree[int i]
stree[i]表示结点i的值
n
补齐后的线段总长
int to_id(int x)
原数据编号到结点编号
int query(int l,int r)
查询[l,r]区间最值
void update(int p,int v)
修改第p个数据为v
const int inf=0x3f3f3f3f;
int stree[4000];
int n;
inline int to_id(int x){return x+n-1;}
int query(int l,int r)
{
int ans=inf;
l=to_id(l);r=to_id(r);
for(int t=l&(-l);l<=r;l=l+t)
{
while(l+t-1>r)t/=2;
ans=min(ans,stree[l/t]);
}
return ans;
}
void update(int p,int v)
{
stree[p=to_id(p)]=v;
while(p=p/2)stree[p]=min(stree[2*p],stree[2*p+1]);
}
int main()
{
...
int nn;
while(~scanf("%d",&nn))
{
//补齐n
n=1;
while(n<nn)n*=2;
//建树
for(int i=n;i<2*n;++i)
{
int tmp=inf;
if(i-n<nn)scanf("%d",&tmp);
stree[i]=tmp;
}
for(int i=n-1;i>0;--i)stree[i]=min(stree[2*i],stree[2*i+1]);
//测试
int l,r;
while(~scanf("%d%d",&l,&r))printf("%d\n",query(l,r));
}
}
标签:实现 增加 补齐 turn amp tree pre span lock
原文地址:https://www.cnblogs.com/maoruimas/p/9739008.html