看起来很数据结构的一道题,其实就是很数据结构...
\(\Theta(nmq)\)的暴力很无脑,是个人应该都会.
\(Code:\) #include #include #include #include #include #include #include #include #include #include #include
然后考虑\(\Theta(n^2)\)怎么做,我们可以对每次操作前的整个矩阵加\(1\)操作维护一个全局标记实现.
我们再对行和列分别维护一个数组记录它最近一次被修改的时间
\(t\).
若当前时间为
\(cur\),询问限制权值为
\(val\),则如果一个点存在横坐标纵坐标的
\(t\)中至少一个满足
\(t-cur\le val\)就是可行点.
我们只需要考虑有多少种连通情况即可.
共八种:
L型:
1.一个点的行和另一个点的列都可行
2.同上,两个点的对应行列都要判
Z型:
3.两个点所在行可行,只需要中间有一列可行即可.
4.两个点所在列可行,只需要中间有一行可行即可.
瞎走型:
5.两点之间所有的行都是可行的
6.两点之间所有的列都是可行的
外绕型:
7.两个点所在行可行,但中间没有可行列,需要到两点纵坐标之外寻找是否存在可行列
8.两个点所在列可行,但中间没有可行行,需要到两点横坐标之外寻找是否存在可行行.
显然,如果两个点连通,那么一定是上面八种情况之一.
于是
\(\Theta(n^2)\)就就解决了.
\(\Theta(n^2)\)的暴力没写,我直接写了正解.
我们再来考虑怎么写没有
\(2\)操作的部分分.
容易发现,如果不存在
\(2\)操作,那么就只需要考虑两个点之间的行是否可行就行了,直接对行建线段树即可.
好了,终于到了正解了!
其实上面的部分分都会了的话,正解就一目了然了.
对行和列分别建一棵线段树,直接维护即可.
但你会发现
\(7,8\)两种操作你不能直接线段树解决,因为你还要最小化距离.
所以我们考虑二分+线段树或线段树上二分.二者的区别在于实现和复杂度一个为
\(\Theta(log_2^2n)\)而另一个为
\(\Theta(log_2n)\).
显然,二分+线段树是两个
\(log\)的,而线段树上二分是一个
\(log\)的.我写的是两个
\(log\)的,反正能过,谁管是啥呢.
因为你需要一段连续能走的,所以你要固定一个端点不动,你二分的是另一个端点的位置.
以点
\((a,b)\)为例,如果你要往左找,那你应该查询的区间是
\([mid,a-1]\),而向左向右缩短/扩张区间需要移动的端点是不一样的,要注意.
\(Code:\) #include #include #include #include #include #include #include #include #include #include #include