JZOJ 6840. 【2020.11.5提高组模拟】铲雪(线段树)
JZOJ 6840. 【2020.11.5提高组模拟】铲雪
题目大意
- n ∗ m n*m n∗m的土地上,每次操作前积雪深度 + 1 +1 +1, q q q次操作,把某行或某列积雪清零,或询问两点间积雪深度不超过某个值的最短路。
- n , m ≤ 1 0 6 n,m\leq10^6 n,m≤106, q ≤ 3 ∗ 1 0 5 q\leq 3*10^5 q≤3∗105
题解
- 这题整张图 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\n");
continue;
}
int sum = abs(s - x) + abs(t - y);
if(i - lx[s] <= k && i - ly[y] <= k) {
printf("%d\n", sum);
continue;
}
if(i - ly[t] <= k && i - lx[x] <= k) {
printf("%d\n", 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\n", 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\n", 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\n", 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\n", ans);
}
}
return 0;
}
哈哈哈哈哈哈哈哈哈哈