【LOJ3159】「NOI2019」弹跳

【题目链接】

  • 点击打开链接

【思路要点】

  • 考虑模拟最短路算法的过程,需要维护一个二维点集,支持矩形 c h k m i n chkmin chkmin ,询问全局最小值,单点删除,并且不能占用过多空间。
  • 显然可以用 K D − T r e e KD-Tree KDTree 解决。
  • 时间复杂度 O ( M N ) O(M\sqrt{N}) O(MN ) ,空间复杂度 O ( N ) O(N) O(N)

【代码】

#include
using namespace std;
const int MAXN = 1e5 + 5;
const int INF = 1e9;
typedef long long ll;
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -f;
	for (; isdigit(ch); ch= getchar()) x = x * 10 + ch - '0';
	x *= f;
}
struct point {int x, y; } p[MAXN];
point min(point a, point b) {return (point) {min(a.x, b.x), min(a.y, b.y)}; }
point max(point a, point b) {return (point) {max(a.x, b.x), max(a.y, b.y)}; }
bool cmptype;
bool cmp(point a, point b) {
	if (cmptype) return a.x < b.x || (a.x == b.x && a.y < b.y);
	else return a.y < b.y || (a.y == b.y && a.x < b.x);
}
bool cnp(int a, int b) {
	return cmp(p[a], p[b]);
}
struct edge {int len; point a, b; };
vector <edge> e[MAXN];
int n, m, w, h, home[MAXN], ans[MAXN];
struct Tree {
	struct Node {
		point pos, rl, rr; int lc, rc;
		int home, tag, Min, Max, Val, vis;
	} a[MAXN];
	int root, size, n;
	void updateval(int root) {
		if (!a[root].vis) {
			a[root].Min = a[root].Val;
			a[root].Max = a[root].Val;
		} else {
			a[root].Min = INF;
			a[root].Max = 0;
		}
		if (a[root].lc) {
			chkmin(a[root].Min, a[a[root].lc].Min);
			chkmax(a[root].Max, a[a[root].lc].Max);
		}
		if (a[root].rc) {
			chkmin(a[root].Min, a[a[root].rc].Min);
			chkmax(a[root].Max, a[a[root].rc].Max);
		}
	}
	void update(int root) {
		if (!a[root].vis) {
			a[root].Min = a[root].Val;
			a[root].Max = a[root].Val;
			a[root].rl = a[root].rr = a[root].pos;
		} else {
			a[root].Min = INF;
			a[root].Max = 0;
			a[root].rl = (point) {INF, INF};
			a[root].rr = (point) {-INF, -INF};
		}
		if (a[root].lc) {
			chkmin(a[root].Min, a[a[root].lc].Min);
			chkmax(a[root].Max, a[a[root].lc].Max);
			chkmin(a[root].rl, a[a[root].lc].rl);
			chkmax(a[root].rr, a[a[root].lc].rr);
		}
		if (a[root].rc) {
			chkmin(a[root].Min, a[a[root].rc].Min);
			chkmax(a[root].Max, a[a[root].rc].Max);
			chkmin(a[root].rl, a[a[root].rc].rl);
			chkmax(a[root].rr, a[a[root].rc].rr);
		}
	}
	int build(int l, int r, bool type) {
		cmptype = type;
		int mid = (l + r) / 2, root = ++size;
		nth_element(home + l, home + mid, home + r + 1, cnp);
		a[root].Val = INF, a[root].vis = false;
		a[root].pos = p[home[mid]];
		a[root].home = home[mid];
		a[root].tag = INF;
		if (a[root].home == 1) a[root].Val = 0;
		if (l < mid) a[root].lc = build(l, mid - 1, type ^ true);
		if (mid < r) a[root].rc = build(mid + 1, r, type ^ true);
		update(root);
		return root;
	}
	void init(int x) {
		n = x;
		for (int i = 1; i <= n; i++)
			home[i] = i;
		root = build(1, n, true);
	}
	void addtag(int root, int val) {
		if (val < a[root].Max && val < a[root].tag) {
			a[root].tag = val;
			a[root].Max = val;
			chkmin(a[root].Min, val);
			if (!a[root].vis) chkmin(a[root].Val, val);
		}
	}
	void pushdown(int root) {
		if (a[root].tag != INF) {
			if (a[root].lc) addtag(a[root].lc, a[root].tag);
			if (a[root].rc) addtag(a[root].rc, a[root].tag);
			a[root].tag = INF;
		}
	}
	int findpos(int root, int val) {
		pushdown(root);
		if (!a[root].vis && a[root].Val == val) {
			a[root].vis = true;
			update(root);
			return root;
		}
		if (a[root].lc && a[a[root].lc].Min == val) {
			int ans = findpos(a[root].lc, val);
			update(root);
			return ans;
		} else {
			assert(a[root].rc && a[a[root].rc].Min == val);
			int ans = findpos(a[root].rc, val);
			update(root);
			return ans;
		}
	}
	void modify(int root, int len, point ql, point qr) {
		pushdown(root);
		if (len >= a[root].Max) return;
		if (ql.x > a[root].rr.x || qr.x < a[root].rl.x || ql.y > a[root].rr.y || qr.y < a[root].rl.y) return;
		if (ql.x <= a[root].rl.x && ql.y <= a[root].rl.y && qr.x >= a[root].rr.x && qr.y >= a[root].rr.y) {
			addtag(root, len);
			return;
		}
		if (!a[root].vis && ql.x <= a[root].pos.x && ql.y <= a[root].pos.y && qr.x >= a[root].pos.x && qr.y >= a[root].pos.y) chkmin(a[root].Val, len);
		if (a[root].lc) modify(a[root].lc, len, ql, qr);
		if (a[root].rc) modify(a[root].rc, len, ql, qr);
		updateval(root);
	}
	void getans() {
		for (int i = 1; i <= n; i++) {
			int pos = findpos(root, a[root].Min);
			ans[a[pos].home] = a[pos].Val;
			int home = a[pos].home;
			for (unsigned j = 0; j < e[home].size(); j++)
				modify(root, e[home][j].len + a[pos].Val, e[home][j].a, e[home][j].b);
		}
		for (int i = 2; i <= n; i++)
			printf("%d\n", ans[i]);
	}
} T;
int main() {
	freopen("jump.in", "r", stdin);
	freopen("jump.out", "w", stdout);
	read(n), read(m), read(w), read(h);
	for (int i = 1; i <= n; i++)
		read(p[i].x), read(p[i].y);
	for (int i = 1; i <= m; i++) {
		int from, len, l, r, d, u;
		read(from), read(len), read(l), read(r), read(d), read(u);
		e[from].push_back((edge) {len, (point) {l, d}, (point) {r, u}});
	}
	T.init(n);
	T.getans();
	return 0;
}

你可能感兴趣的:(【OJ】LOJ,【类型】做题记录,【数据结构】KD-Tree,【算法】最短路)