JZOJ 6840. 【2020.11.5提高组模拟】铲雪
题目大意
n
∗
m
n*m
n ∗ m 的土地上,每次操作前积雪深度
+
1
+1
+ 1 ,
q
q
q 次操作,把某行或某列积雪清零,或询问两点间积雪深度不超过某个值的最短路。
n
,
m
≤
1
0
6
n,mleq10^6
n , m ≤ 1 0 6 ,
q
≤
3
∗
1
0
5
qleq 3*10^5
q ≤ 3 ∗ 1 0 5
题解
这题整张图
n
∗
m
n*m
n ∗ m 特别大,直接跑最短路显然不可行,但稍微推一推,发现这题和最短路完全没关系,由于这题操作的特殊性,所以时刻
i
i
i 时两点
(
s
,
t
)
(s,t)
( s , t ) 和
(
x
,
y
)
(x,y)
( x , y ) 之间最短路只有如下几种情况: 先令
S
=
∣
s
−
x
∣
+
∣
t
−
y
∣
S=|s-x|+|t-y|
S = ∣ s − x ∣ + ∣ t − y ∣ 1、
[
s
,
x
]
[s,x]
[ s , x ] 中每一行或
[
t
,
y
]
[t,y]
[ t , y ] 中每一列可走,则最短路为
S
S
S ; 2、第
s
s
s 行及第
y
y
y 列或第
t
t
t 列及第
x
x
x 行可走,则最短路为
S
S
S ; 3、第
s
s
s 行及第
x
x
x 行可走,
[
t
,
y
]
[t,y]
[ t , y ] 中某一列可走,则最短路为
S
S
S ,纵向同理; 4、第
s
s
s 行及第
x
x
x 行可走,有
[
1
,
t
)
[1,t)
[ 1 , t ) 中(或
(
y
,
m
]
(y,m]
( y , m ] 中)第
j
j
j 列可走,则最短路为
S
+
2
(
t
−
j
)
S+2(t-j)
S + 2 ( t − j ) (或
S
+
2
(
j
−
y
)
S+2(j-y)
S + 2 ( j − y ) ),纵向同理。 为什么没有其它路径曲折的情况呢? 简单的画图可以发现,如果路径更曲折的情况走的通,那么前几种情况中某种也能走的通,且路径会更短,所以其它的不需要考虑。 直接对行和列分别开一棵线段树维护即可。
代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 1000010
int lx[ N] , ly[ N] ;
struct {
struct {
int mx = 0 , mi = 0 ;
} f[ N * 4 ] ;
void ch ( int v, int l, int r, int x, int c) {
if ( l == r) f[ v] . mi = f[ v] . mx = c;
else {
int mid = ( l + r) / 2 ;
if ( x <= mid) ch ( v * 2 , l, mid, x, c) ; else ch ( v * 2 + 1 , mid + 1 , r, x, c) ;
f[ v] . mi = min ( f[ v * 2 ] . mi, f[ v * 2 + 1 ] . mi) ;
f[ v] . mx = max ( f[ v * 2 ] . mx, f[ v * 2 + 1 ] . mx) ;
}
}
int fmi ( int v, int l, int r, int x, int y) {
if ( l == x && r == y) return f[ v] . mi;
int mid = ( l + r) / 2 ;
if ( y <= mid) return fmi ( v * 2 , l, mid, x, y) ;
if ( x > mid) return fmi ( v * 2 + 1 , mid + 1 , r, x, y) ;
return min ( fmi ( v * 2 , l, mid, x, mid) , fmi ( v * 2 + 1 , mid + 1 , r, mid + 1 , y) ) ;
}
int fmx ( int v, int l, int r, int x, int y) {
if ( l == x && r == y) return f[ v] . mx;
int mid = ( l + r) / 2 ;
if ( y <= mid) return fmx ( v * 2 , l, mid, x, y) ;
if ( x > mid) return fmx ( v * 2 + 1 , mid + 1 , r, x, y) ;
return max ( fmx ( v * 2 , l, mid, x, mid) , fmx ( v * 2 + 1 , mid + 1 , r, mid + 1 , y) ) ;
}
int gtl ( int v, int l, int r, int x, int y, int c) {
if ( l == r) {
if ( f[ v] . mx >= c) return l;
return 1e9 ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) return gtl ( v * 2 , l, mid, x, y, c) ;
if ( x > mid) return gtl ( v * 2 + 1 , mid + 1 , r, x, y, c) ;
if ( fmx ( v * 2 , l, mid, x, mid) >= c) return gtl ( v * 2 , l, mid, x, mid, c) ;
return gtl ( v * 2 + 1 , mid + 1 , r, mid + 1 , y, c) ;
}
int gtr ( int v, int l, int r, int x, int y, int c) {
if ( l == r) {
if ( f[ v] . mx >= c) return l;
return - 1e9 ;
}
int mid = ( l + r) / 2 ;
if ( y <= mid) return gtr ( v * 2 , l, mid, x, y, c) ;
if ( x > mid) return gtr ( v * 2 + 1 , mid + 1 , r, x, y, c) ;
if ( fmx ( v * 2 + 1 , mid + 1 , r, mid + 1 , y) >= c) return gtr ( v * 2 + 1 , mid + 1 , r, mid + 1 , y, c) ;
return gtr ( v * 2 , l, mid, x, mid, c) ;
}
} a, b;
int main ( ) {
int n, m, Q, op, s, t, x, y, i, k;
scanf ( "%d%d%d" , & n, & m, & Q) ;
for ( i = 1 ; i <= Q; i++ ) {
scanf ( "%d" , & op) ;
if ( op == 1 ) {
scanf ( "%d" , & x) ;
a. ch ( 1 , 1 , n, x, i) ;
lx[ x] = i;
}
else if ( op == 2 ) {
scanf ( "%d" , & x) ;
b. ch ( 1 , 1 , m, x, i) ;
ly[ x] = i;
}
else if ( op == 3 ) {
scanf ( "%d%d%d%d%d" , & s, & t, & x, & y, & k) ;
if ( i - max ( lx[ s] , ly[ t] ) > k || i - max ( lx[ x] , ly[ y] ) > k) {
printf ( "-1
" ) ;
continue ;
}
int sum = abs ( s - x) + abs ( t - y) ;
if ( i - lx[ s] <= k && i - ly[ y] <= k) {
printf ( "%d
" , sum) ;
continue ;
}
if ( i - ly[ t] <= k && i - lx[ x] <= k) {
printf ( "%d
" , sum) ;
continue ;
}
if ( i - a. fmi ( 1 , 1 , n, min ( s, x) , max ( s, x) ) <= k || i - b. fmi ( 1 , 1 , m, min ( t, y) , max ( t, y) ) <= k) {
printf ( "%d
" , sum) ;
continue ;
}
int ans = 1e9 ;
if ( i - lx[ s] <= k && i - lx[ x] <= k) {
if ( i - b. fmx ( 1 , 1 , m, min ( t, y) , max ( t, y) ) <= k) {
printf ( "%d
" , sum) ;
continue ;
}
int s0 = - 1e9 , s1 = 1e9 ;
if ( min ( t, y) > 1 ) s0 = b. gtr ( 1 , 1 , m, 1 , min ( t, y) - 1 , i - k) ;
if ( max ( t, y) < m) s1 = b. gtl ( 1 , 1 , m, max ( t, y) + 1 , m, i - k) ;
ans = min ( ans, sum + 2 * ( min ( t, y) - s0) ) ;
ans = min ( ans, sum + 2 * ( s1 - max ( t, y) ) ) ;
}
if ( i - ly[ t] <= k && i - ly[ y] <= k) {
if ( i - a. fmx ( 1 , 1 , n, min ( s, x) , max ( s, x) ) <= k) {
printf ( "%d
" , sum) ;
continue ;
}
int s0 = - 1e9 , s1 = 1e9 ;
if ( min ( s, x) > 1 ) s0 = a. gtr ( 1 , 1 , n, 1 , min ( s, x) - 1 , i - k) ;
if ( max ( s, x) < n) s1 = a. gtl ( 1 , 1 , n, max ( s, x) + 1 , n, i - k) ;
ans = min ( ans, sum + 2 * ( min ( s, x) - s0) ) ;
ans = min ( ans, sum + 2 * ( s1 - max ( s, x) ) ) ;
}
if ( ans == 1e9 ) ans = - 1 ;
printf ( "%d
" , ans) ;
}
}
return 0 ;
}