[代码]HDU 4400 Mines
Abstract
HDU 4400 Mines
x坐标法……
Body
Source
http://acm.hdu.edu.cn/showproblem.php?pid=4400
Description
给定N个点的平面点集(可能有重点),每个点向与其曼哈顿距离不超过d[i]的点连边。每次询问拿走某个点及其传递闭包,问总共拿走多少个点。
Solution
其实是很没节操的题,暴力做就是了……不过今天卡得眼泪汪汪所以就没做到。
把x坐标离散化后每个点塞到相应x坐标的multiset里。查询时就二分一下x坐标的范围,然后对范围内的每个multiset再二分y坐标。之后就是简单的标记和BFS了……
正解的话,我猜是kd树,或者是树套树?
Code
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #include <set> #include <algorithm> using namespace std; struct snode { int y, id; snode() {} snode(int a, int b): y(a), id(b) {} bool operator<(const snode &rhs) const { return y<rhs.y; } }; typedef multiset<snode>::iterator itr; int N, M, X; int hash[111111]; int x[111111], y[111111], d[111111]; bool vis[111111]; multiset<snode> p[111111]; queue<int> q; int main() { int i, j, k; int t = 0; while (cin>>N, N) { for (i = 0; i < N; ++i) { scanf("%d%d%d", x+i, y+i, d+i); hash[i] = x[i]; } sort(hash, hash+N); X = unique(hash, hash+N)-hash; for (i = 0; i < X; ++i) p[i].clear(); for (i = 0; i < N; ++i) { j = lower_bound(hash, hash+X, x[i])-hash; p[j].insert(snode(y[i], i)); } memset(vis, 0, sizeof vis); cin>>M; printf("Case #%d:\n", ++t); while (M--) { scanf("%d", &k); k--; if (vis[k]) { puts("0"); continue; } vis[k] = 1; q.push(k); int l, r, dy; int cnt = 0; itr yl, yr; while (!q.empty()) { ++cnt; k = q.front(); q.pop(); l = lower_bound(hash, hash+X, x[k]-d[k])-hash; r = upper_bound(hash, hash+X, x[k]+d[k])-hash; for (i = l; i < r; ++i) { dy = d[k]-abs(x[k]-hash[i]); yl = p[i].lower_bound(snode(y[k]-dy, 0)); yr = p[i].upper_bound(snode(y[k]+dy, 0)); for (itr it = yl; it != yr; ++it) if (!vis[it->id]) { vis[it->id] = 1; q.push(it->id); } p[i].erase(yl, yr); } } printf("%d\n", cnt); } } return 0; }