JZOJ 6840. 【2020.11.5提高组模拟】铲雪(线段树)

JZOJ 6840. 【2020.11.5提高组模拟】铲雪

题目大意

  • n ∗ m n*m nm的土地上,每次操作前积雪深度 + 1 +1 +1 q q q次操作,把某行或某列积雪清零,或询问两点间积雪深度不超过某个值的最短路。
  • n , m ≤ 1 0 6 n,m\leq10^6 n,m106 q ≤ 3 ∗ 1 0 5 q\leq 3*10^5 q3105

题解

  • 这题整张图 n ∗ m n*m nm特别大,直接跑最短路显然不可行,但稍微推一推,发现这题和最短路完全没关系,由于这题操作的特殊性,所以时刻 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=sx+ty
  • 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(tj)(或 S + 2 ( j − y ) S+2(j-y) S+2(jy)),纵向同理。
  • 为什么没有其它路径曲折的情况呢?
  • 简单的画图可以发现,如果路径更曲折的情况走的通,那么前几种情况中某种也能走的通,且路径会更短,所以其它的不需要考虑。
  • 直接对行和列分别开一棵线段树维护即可。

代码

#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;
}
posted @ 2020-11-05 21:14  AnAn_119  阅读(74)  评论(0编辑  收藏  举报