写这篇博客的目的不是介绍树状数组求区间最大值的方法,而是想说,树状数组在支持单点修改+区间查询时对于区间最值的维护是错误的;
俺不知道其他的博客是咋写出来的,但是我今天在做一道题的时候,由于不想用线段树(其实是不会,忘了咋用)就去查了一下树状数组的方法,别说还真能查到,在这里就不放博客了;但是想说一些树状数组求区间最值的错误(在有值修改时候的错误)
初始:有一个tree的数组,其中tree[i]代表了a数组在[i-lowbit[i],i]区间上的最小值
在这种情况下,假定a[2]=1,并且在tree[4]上记录有tree[4]=1;此时a[3]=1;修改a[2]为2,这时向上传播,传到tree[4]的时候,tree[4]=min(tree[4],a[2]),这个时候这个值没有被修改,这是很合理的(因为这个最小值是由a[3]产生的)。
但是在刚才的讨论中如果a[3]=2;
tree[4]还是1,a[2]=1,此时,我要把a[2]的值改成2,发现我还是没改成功,为啥?a[2]还是比tree[4]大啊,必然改不了,但是这个时候就不对了,你把a[2]改成2的时候,这个tree[4]上的最小值不是由a[3]产生的了,所以这时候就出问题了;一些博客介绍查询的方法的确很新颖,但是更新就有问题,至少不应该用求和的方式去更新数组。
好了再说用线段树的方法,我认为线段树对付区间求最值就很用,你更新一个小子区间的时候,你能知道其他区间是啥情况,不会混到一起。
int lowbit(int x)
{
return x & (-x);
}
//int build(int l, int r)//这个应该是O(logn)的复杂度
//{
// for (int i = l; i < r; i++)
// {
// int t = i;
// while (t < r)
// {
// tree[t] = min(tree[t], a[i].mn);//sort之后的
// t = t + lowbit(t);
// }
// }
//}这块我觉得应该不用build之后直接更新就行了
void update(int L, int v, int r, int a)
{
while (L < r)
{
if (a == -1)
{
if (v < tree[L])
{
tree[L] = v;
count1[L] = 1;
}
else if (v == tree[L])
{
count1[L]++;
}
}
else if (tree[L] == a)
{
if (count1[L] == 1)
tree[L] = v;
}
L = L + lowbit(L);
}
}
int query(int l, int r)
{
int ans = INT_MAX;
while (r >= l)
{
r--;
for (; (r - lowbit(r)) >= l && r != 0; )
{
ans = min(ans, tree[r]);
r = r - lowbit(r);
}
}
return ans;
}
乐死了,用这个就图一乐吧,改一晚上了,发现是这有问题,heheheh