纪念碑

137 篇文章 1 订阅
12 篇文章 0 订阅

题目

题意概要
有一个 n × m n\times m n×m 的方格图,其中有 p p p 个矩形建筑。求图中没有与矩形重叠的正方形中最大的一个。

数据范围与约定
n , m ≤ 1 0 6 , p ≤ 4 × 1 0 4 n,m\le 10^6,p\le 4\times 10^4 n,m106,p4×104

思路

使用类似于 尺取法 的方法。或者叫做双扫描线吧。平行于 y y y 轴的扫描线。

对于左端点是 l l l 、右端点是 r r r 的情况,我们认为在这之间存在边长为 r − l + 1 r-l+1 rl+1 的正方形。试图将 r r r 增大一,我们求一个最宽的上下界 u , d u,d u,d ,满足第 u u u 行、第 u + 1 u+1 u+1 行、第 u + 2 u+2 u+2 行,一直到第 d d d 行,都是没有建筑物的。

形如

在这里插入图片描述

如果这个空隙 u − d + 1 u-d+1 ud+1 是大于等于 r − l r-l rl 的,那么就可以将 r r r 增大 1 1 1

这个空隙的大小,可以使用线段树解决。解决一个 “最长全零子段” 的问题。

维护线段树,可以通过 “遇到右端点就区间减、左端点就区间加” 的方法。

然后没了。如果你对时间复杂度 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 不太放心,有几个优化:

  • 对纵坐标进行离散化,线段树的值域降为 O ( p ) \mathcal O(p) O(p) 的。
  • 对横坐标进行离散化(注意到合法的、最大的 r r r 总是在某个建筑的左端点旁边),尺取次数降为 O ( p ) \mathcal O(p) O(p)

两者同时使用,理论上来说,是 O ( p log ⁡ p ) \mathcal O(p\log p) O(plogp) 的。但是伪代码中没有使用;你也没必要做的这么绝。

代码

此处仅提供伪代码作为参考。因为我还没写出来

SegmentTree st;
void work(){
	int l = 1, r = 0, ans = 0;
	while(r != n and l <= n){
		while(r < n){
			for(左端点是第r+1列的矩形mat)
				在线段树中将[up,down]增大1
			if(st.query() >= r-l)
				++ r; // query() 为最大全零子段
			else 撤销本轮的add操作 
		}
		ans = max(ans,r-l+1);
		for(右端点是第l列的矩形mat)
			在线段树中将[up,down]减少1
		++ l; // 强制移动一下l 
	}
	cout << ans << endl;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值