树状数组维护区间最值
\(update : 2022.2.1\)
学习原文
没错 , 树状数组也能维护区间最值.(单点修改 , 区间查询)
不过这种写法要对树状数组维护的区间要有一定的理解.
主要是理解 tree[x] 维护的区间 [x - lowbit(x) + 1 , x] 的最值
单点修改
//将 a[x] 修改为 y.
void updata(int x,int y){
tree[x] = a[x] = y ; // 这里我的思考与原作有冲突.
while( x<= n){
//tree[x] = y ; 原作在这里加上了更新.
int low = lowbit(x);
for(i=1;i<low;i<<=1) //这里为什么是i<<=1? , 去观察树状数组维护的区间[x-lowbit(x),x] , 都是跟 x 差 2 的次方倍 ; 注意 i < w 的细节 , 举例 8 (i = 1 , 2, 4 ) , 若 <= 则有 i = 8 , tree[0] 的加入.
tree[x] = max(tree[x] , tree[x - i]); // 注意是tree数组 , 有是定义域上的一点代表 a 数组的一个区间 , 用 lowbit , 往回推一定可以能覆盖到一开始 a[x] 修改为 y 的影响.
x += low;
}
}
区间查询
int ask(int x,int y){
int ans = 0;
while( y>=x ){
ans = max(ans , a[y]) , y -= 1; //这里为什么要这样做?我要去除我这一点,在找我的子区间;
for(;y-lowbit(y)>=x;)//我维护的子区间大于x , 我这个 x 才有用.
ans = max(ans , tree[y]);
y -= lowbit(y);
}
//等价于for(;y-lowbit(y)>=x;y-lowbit(y)) //判断->执行->减->判断....
return ans;
}
例题 :
HDU 1754
#include <bits/stdc++.h>
using ll = long long;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n,m;
while(std::cin >> n >> m) {
std::vector<int> a(n + 1) , tr(n + 1 , 0);
auto lowbit = [&](int x) -> int {
return x & -x;
};
auto update = [&](int x) -> void {
tr[x] = a[x]; //仅需在开头更新 , 这句话并不需要放在 while 循环中第一句中
while (x <= n) {
int len = lowbit(x);
//这里利用树状数组构造的性质
//①子区间的个数等于 lowbit 的位数 ( 看蓝书开头如何划分一个数的区间的 )
//②子区间编号与父区间编号差 (1 >> i)
for(int i = 1 ; i < len ; i<<=1 ) {
tr[x] = std::max(tr[x] , tr[x - i]);
}
x += lowbit(x); //利用性质与父亲结点差 lowbit(x)
}
};
auto get = [&](int x,int y) -> int{
int ans = 0;
while(y >= x) {
ans = std::max(ans , a[y]) ; --y;
while(y - lowbit(y) - 1 >= x) { //如果 y - lowbit(y) + 1 , y - lowbit(y)可能变为 0 , lowbit(y)死循环.
ans = std::max(ans , tr[y]);
y -= lowbit(y);
if(y == 0) break;
}
}
return ans;
};
for(int i = 1 ; i <= n ; ++i) {
std::cin >> a[i];
update(i);
}
while (m--) {
char opt ;
std::cin >> opt;
if(opt == 'Q') {
int l,r;
std::cin >> l >> r;
std::cout << get(l , r) << '\n';
} else {
int x,val;
std::cin >> x >> val;
a[x] = val;
update(x);
}
}
}
}
update
#include <bits/stdc++.h>
using ll = long long;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
int n,m;
while (std::cin >> n >> m) {
std::vector<int> a(n + 1);
std::vector<int> tr(n + 1);
auto lowbit = [&] (int x) {
return x & (-x);
};
auto update = [&] (int x , int val) {
tr[x] = std::max(tr[x] , val);
//x += lowbit(x);
while (x <= n) {
int len = lowbit(x);
for (int i = 1 ; i < len ; i <<= 1) {
tr[x] = std::max(tr[x] , tr[x - i]);
}
x += lowbit(x);
}
};
auto query = [&] (int x,int y) {
int ans = 0;
while (y >= x) {
ans = std::max(ans , a[y]) ; --y; //这种情况应对 y - lowbit(y) + 1 < x , 只能一个个减
if (y == 0) break;
while (y - lowbit(y) + 1 >= x) {
ans = std::max(ans , tr[y]);
y -= lowbit(y);
if (y == 0) break;
}
}
return ans;
};
for (int i = 1 ; i <= n ; ++i) {
std::cin >> a[i];
update(i , a[i]);
}
while (m--) {
std::string opt;
std::cin >> opt;
if (opt[0] == 'Q') {
int l,r;
std::cin >> l >> r;
std::cout << query(l , r) << '\n';
} else {
int x,val;
std::cin >> x >> val;
a[x] = val;
update(x , val);
}
}
}
return 0;
}