[Code+#3]寻找车位—— 嵌套结构 线段树


题意

有一个长度为 \(n \times m\) 的矩阵,保证 \(n \leq m\) ,且 \(n \times m \leq 10^6,1\leq q \leq 3000\)
支持两种操作:

  1. 询问某一子矩阵内最大全 \(0\) 矩阵大小
  2. 单点修改

思路

考虑这东西暴力怎么做。

扫描线,把某一维扫掉。可以发现随着左端点的移动,最优可行右端点单调不减。
如果是朴素做法,就是对上下端点建一个 RMQ 然后大力枚举上端点,判断可行性。单次时间 \(O(nmq+nmlogn)\)
进一步的,我们可以发现,对于上端点的最优下端点也单调不减,可以把 \(RMQ\) 也省略掉,搞个单调队列。时间复杂度 \(O(nmq)\)

两个单调队列,似乎没前途了啊。
树套树(? 空间开不下
离线下来扫描线(? 维护的信息有最值和时间两部分,二次离线不现实且难以实现。
分块(? \(O(nm+qn\sqrt{m})\) 答案是寄

等等... \(n\) 是不是极小,由于 \(n \leq m\) 因此是根号级别的。
那树套树我不写爆啊 (空间还是开不下)
那单次 \(O(nlogm)\) 的复杂度就是可行的,要吃低保就拉满。

考虑对行建立一个线段树,节点上维护其对应的 \((x,y\in [l,r])\) 的信息。
考虑修改,怎么快速合并? 考虑两个区间只有向左右伸出的 全 \(0\) 最长矩形才会影响答案,因此合并(pushup)的时候直接 \(O(n)\) 大力处理(有点像DDP),线段树共有 \(O(log m)\) 层,故修改复杂度是
\(O(nlogm)\) 的。
查询依法炮制,直接与答案进行区间合并即可
例子:
\([l,mid]\) ------->\([l,mid]\) (向右侧伸出)
0 0 1 1 1 ------->3
0 1 1 1 1 ------->4
0 1 0 1 1 ------->2
0 1 0 0 1 ------->1

\([mid+1,r]\) ------->\([mid+1,r]\) (向左侧伸出)
1 1 1 1 0 ------->4
1 1 1 0 0 ------->3
1 1 0 1 0 ------->2
0 1 0 1 0 ------->0

合并后新产生的矩阵即为
\([l,r]\)---------------------------->\([l,r]\)(中间更新的答案)
0 0 1 1 1 1 1 1 1 0 ------->3+4=7
0 1 1 1 1 1 1 1 0 0 ------->4+3=7
0 1 0 1 1 1 1 0 1 0 ------->2+2=4
0 1 0 0 1 0 1 0 1 0 ------->1+0=0

对于然后对于中心的更新答案,单次 \(O(m)\)
发现随着上端点的移动,最优下端点单调不减。直接用 RMQ 判断即可。
如果你觉得 \(RMQ\) 不符合简洁明了,常数极小的原则。
那就用单调队列/se
总之时间复杂度可以实现 RMQ 的\(O(nm+nqlog^2m)\)
或者单调队列的 \(O(nm+nqlogm)\)

也算是数据结构嵌套的优质题(?