树状数组维护区间最值

\(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;
}

posted @ 2022-02-01 16:11  xqy2003  阅读(428)  评论(0)    收藏  举报