网格上有N(<=5e4)堵墙,有M(<=5e4)只鸟,其会选择最近的那堵墙撞晕,求鸟撞到各堵墙的次数。
考试时给的中文翻译不忍直视。。貌似还是从某题解直接抄过来的。。直接看英文了。。
然后就在POJ上排#13了。。
首先离散化一下。。
然后因为只能上下左右4个方向飞情况类似,这里我们只需要讨论一个方向。
考虑向上飞的情况,我们人为添加一条下边界扫描,同时维护横着的墙,显然,如果遇到了新的墙,肯定目前其覆盖范围就是最优的,因此考虑线段树维护墙,遇到了新墙,就覆盖了对应的线段;遇到了鸟,那么只要查询线段树即可。
#include
#include
#include
#define rep(i,j,k) for(int i=j;i
#define ms(i,j,k) memset(i,j,sizeof(int)*k)
using namespace std;
const int N = 50005, S = N * 3;
int wall, tot;
int dis[N], v[N], w[N], c[S * 3];
int x[S], y[S], rx[S], ry[S], xs[S], ys[S], px[S], py[S];
int *num;
bool cmp(int a, int b) { return num[a] < num[b]; }
void relabel(int *x, int *r, int tot, int *a, int *mp) {
int k, p, m = 0;
rep(i,0,tot) r[i] = i;
num = x;
sort(r, r + tot, cmp);
a[r[0]] = ++m; mp[m] = x[r[0]];
rep(i,1,tot) {
k = r[i]; p = r[i - 1];
if (x[k] != x[p]) a[k] = ++m, mp[m] = x[k];
else a[k] = m;
}
}
int get(int t, int l, int r, int q) {
if (c[t] != -2) return c[t];
int mid = l + r >> 1;
if (q <= mid) return get(t * 2, l, mid, q);
else return get(t * 2 + 1, mid + 1, r, q);
}
void set(int t, int l, int r, int ql, int qr, int qc) {
if (ql <= l && r <= qr) { c[t] = qc; return; }
if (c[t] != -2) {
c[t * 2] = c[t * 2 + 1] = c[t];
c[t] = -2;
}
int mid = l + r >> 1;
if (ql <= mid) set(t * 2, l, mid, ql, qr, qc);
if (qr > mid) set(t * 2 + 1, mid + 1, r, ql, qr, qc);
}
void scan(int k, int *ys, int *xs, int *py, int n) {
if (k < wall) { // wall
int k2 = k ^ 1;
if (xs[k2] >= xs[k])
set(1, 1, n, xs[k], xs[k2], k / 2);
} else { // bird
int t = get(1, 1, n, xs[k]);
if (~t) {
int d = min(abs(py[ys[k]] - py[ys[t * 2]]), abs(py[ys[k]] - py[ys[t * 2 + 1]]));
k -= wall;
if (d < dis[k]) dis[k] = d, v[k] = t;
}
}
}
void fly(int *ry, int *ys, int *xs, int *py, int n) {
c[1] = -1;
rep(i,0,tot) scan(ry[i], ys, xs, py, n);
c[1] = -1;
for(int i=tot-1;i>=0;--i) scan(ry[i], ys, xs, py, n);
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
wall = n * 2; tot = wall + m;
rep(i,0,tot) scanf("%d%d", x + i, y + i);
relabel(x, rx, tot, xs, px);
relabel(y, ry, tot, ys, py);
ms(dis, 0x7f, m); ms(w, 0, n);
fly(ry, ys, xs, py, xs[rx[tot - 1]]);
fly(rx, xs, ys, px, ys[ry[tot - 1]]);
rep(i,0,m) ++w[v[i]];
rep(i,0,n) printf("%d\n", w[i]);
return 0;
}
Time Limit: 6000MS Memory Limit: 131072K
Total Submissions: 1536 Accepted: 246
Case Time Limit: 3000MS
There are N walls. A wall has an infinity height, so it looks like a segment in a plane from high sky. Obviously, they don’t intersect. Let’s take a series of interesting experiments. Everytime, we put a lovely bird called Xiaoniao in the place. Then, she will choose any one of four possible directions paralleled to axes and disregarded anything else but fly forward. It may occur that she touch a wall and fainted. So poor Xiaoniao is, she always choose the direction which made her fainted as early as possible. You’re asked to count, how many times did Xiaoniao touched each wall.
It is guaranteed that each time there will be exactly one direction that makes Xiaoniao faints as early as possible. I.E. She won’t have no choice to get faint, neither have more than one direction producing the same fainting time. Xiaoniao won’t be placed on a wall, either. Touching an end point of a wall is also considered a touch.
The first line contains N and M (both not exceeding 50,000). M is the number we put Xiaoniao in the place.
The following N lines describe the walls. Each line consists 4 integers x1, y1, x2, y2, meaning a wall from (x1,y1) to (x2,y2). The wall is always parallel to the coordinate axes.
The next M lines describe where we put Xiaoniao. Each line consists 2 integers x and y. This means we put Xiaoniao at the point (x,y).
N lines, i-th line contains one integer that is the number of Xiaoniao touches the i-th wall.
4 4
10 0 10 40
0 40 40 40
10 10 50 10
40 50 40 10
15 12
12 35
35 38
38 15
1
1
1
1
POJ Monthly–2007.11.25, Zhou Dong