纪念碑
发布日期:2021-05-07 01:01:50 浏览次数:15 分类:精选文章

本文共 1175 字,大约阅读时间需要 3 分钟。

题目

题意概要

有一个 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;}
上一篇:CSS总结div中的内容垂直居中的四种方法
下一篇:纯css实现容器高度随宽度等比例变化的两种解决方案

发表评论

最新留言

留言是一种美德,欢迎回访!
[***.207.175.100]2025年03月23日 20时20分19秒