力扣 leetcode 699.掉落的方块(线段树&离散化)

leetcode 699.掉落的方块(线段树&离散化)


tag:线段树、离散化。
题意: 给出二维数组positions(代码中改为f),每一项f[i] = [left , lenghth],left表示左边界,length表示从左边届到右边界的距离。方块为正方形(高等同于宽),现按顺序从无穷高掉落方块,方块在下落过程若有遇到方块则会立马停止定住不动(类似俄罗斯方块规则),求每块方块落下后的整个图的最大高度。
数据范围:方块数 <= 1e3 , left <= 1e8 , length <= 1e6。
思路: 将题目转化成求整个范围的最大值,初始全部为0,后面下落方块由于会在其范围最高处停下,即将方块范围内的值全部重置成maxh[l,r] + h(方块范围d的原本最高值+方块高)。由于坐标点跨度过大, 直接用线段树维护数据范围过大,数组无疑会越界,故须对坐标点进行离散化。
注意: 需要注意的是边界处理,如[3,4]与[4,6]不叠加,但在使用线段树时明显会产生叠加,弱化边界为左闭右开[3,4) , [4,6),在实际代码中直接将右边界-1即可,即[3,3] , [4,5]。

代码:
// LH
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef vector<int> VI;
typedef vector<ll> VL;
typedef vector<PII> VPII;
typedef vector<PLL> VPLL;
const int N = 2e3 + 3;
//掉落的方块
//线段树、离散化
//范围重置,维护范围最大值
/*
转化为范围重置,查询范围最大值,需要注意边界处理,如[3,4]与[4,6]不叠加,但在使用线段树时明显会产生叠加,弱化边界为左闭右开[3,4) , [4,6)
在实际操作中直接右边界-1即可,即[3,3] , [4,5]。
由于数据原因需要对坐标点进行离散化
*/
class Solution {
public:
int ls(int x) {return x << 1;}
int rs(int x) {return x << 1 | 1;}
ll tree[N<<2] , tag[N<<2];
map<int,int> ff;
int n;
inline void up(int p) {tree[p] = max(tree[ls(p)] , tree[rs(p)]);}
inline void down(int p , int l , int r) {;
	if(tag[p]) {
		tag[ls(p)] = tag[p];
		tag[rs(p)] = tag[p];
		tree[ls(p)] = tag[p];
		tree[rs(p)] = tag[p];
		tag[p] = 0;
	}
}
inline void update(int l , int r , int p , int lx , int rx , int x) {
	if(lx <= l && r <= rx) {
		tree[p] = x;
		tag[p] = x;
        cout << tree[p] << '\n';
		return;
	}
	down(p , l , r);
	int mid = l + r >> 1;
	if(lx <= mid) update(l , mid , ls(p) , lx , rx , x);
	if(rx > mid) update(mid+1 , r , rs(p) , lx , rx , x);
	up(p);
}
inline int query(int l , int r , int p , int lx , int rx) {
	if(lx <= l && r <= rx) {
		return tree[p];
	}
	down(p , l , r);
	int mid = l + r >> 1;
	int res = 0;
	if(lx <= mid) res = max(res , query(l , mid , ls(p) , lx , rx));
	if(rx > mid) res = max(res , query(mid+1 , r , rs(p) , lx , rx));
	return res;
}
    vector<int> fallingSquares(vector<vector<int>>& f) {
        vector<int> fff;
        for(int i = 0;i < f.size();i ++) {
            fff.emplace_back(f[i][0]);
            f[i][1] += f[i][0] - 1;		//将f[i][1]转化成方块右边界坐标-1
            fff.emplace_back(f[i][1]);
        }
        //排序&去重,进行离散化
        sort(fff.begin() , fff.end());
        fff.resize(unique(fff.begin() , fff.end()) - fff.begin());
        for(int i = 0;i < fff.size();i ++) {
            ff[fff[i]] = i+1;
        }
        n = ff[fff.back()];
        vector<int> ans;
        for(int i = 0;i < f.size();i ++) {
            int l = ff[f[i][0]] , r = ff[f[i][1]] , h = f[i][1] - f[i][0] + 1 + query(1 , n , 1 , l , r);	//将方块范围内高度重置为范围内最高值+方块高
            update(1 , n , 1 , l , r , h);
            ans.emplace_back(tree[1]);
        }
        return ans;
    }
};
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值