
傻鸟:在二维平面上有N堵水平或垂直的墙,放M只傻鸟,每只傻鸟会撞死在最近的那堵墙上。求最后每堵墙上有多少团血肉模糊的尸体!
3.3活用各种数据结构
线段树和平方分割
中国人出的题目就是这么和谐,不过难度还是有的。思路类似于黑白棋 POJ 3109 Inner Vertices 的扫描线算法,一层一层地染色。首先只考虑傻鸟垂直飞的情况,从Y坐标大的地方往下扫描(此时小鸟相当于往上飞,相对运动嘛)。用一个线段树表示当前区间属于哪堵墙的地盘,每堵墙的x1,x2坐标作为l和r,区间的值为自己的id。扫描线往下移动的过程中就是一个用id染色的过程,如果碰到鸟了,那么鸟的x坐标送到线段树里查到的id就是它要撞死的墙。
同理,水平飞行的时候只要将坐标反过来就行了。需要注意的是,出题人非常不严谨,没有告知坐标的最大范围,事实上这个值比0x3f3f3f3f大,害得我WA了一大天!
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
#define LEFT(x) (x << 1)
#define RIGHT(x) ((x << 1) | 1)
#define MID(x, y) ((x + y) >> 1)
#define MAXN 200010
enum Type
{
WALL, BIRD
};
struct Distance
{
int id, d; // 距离最近的墙的id以及距离
Distance()
{
d = INT_MAX; // 0x3f3f3f3f让我WA了无数次(┳_┳)...
}
};
Distance the_distance[MAXN];
struct Wall
{
int x1, y1, x2, y2;
}wall[MAXN];
struct Bird
{
int x, y;
}bird[MAXN];
struct Object
{
int x;
int y1, y2;
int id;
Type type;
Object(int x, int y1, int y2, int id, Type type) : x(x), y1(y1), y2(y2), id(id), type(type) {};
bool operator < (const Object& other) const
{
return x < other.x;
}
};
vector <int> listx;
vector <int> listy;
int result[MAXN];
int N, M;
struct SegmentTree
{
int left[MAXN * 8], right[MAXN * 8], value[MAXN * 8];
void build(int p, int l, int r)
{
left[p] = l;
right[p] = r;
value[p] = 0;
if (l < r)
{
int mid = MID(l, r);
build(LEFT(p), l, mid);
build(RIGHT(p), mid + 1, r);
}
}
void set(int p, int l, int r, int v)
{
if (left[p] == l && right[p] == r)
{
value[p] = v;
return;
}
if (value[p] > 0)
{
value[LEFT(p)] = value[p];
value[RIGHT(p)] = value[p];
value[p] = 0;
}
int mid = MID(left[p], right[p]);
if (l > mid)
{
set(RIGHT(p), l, r, v);
}
else if (r <= mid)
{
set(LEFT(p), l, r, v);
}
else
{
set(LEFT(p), l, mid, v);
set(RIGHT(p), mid + 1, r, v);
}
}
int get(int p, int l)
{
if (left[p] == right[p] && left[p] == l)
{
return value[p];
}
if (value[p] > 0)
{
value[LEFT(p)] = value[p];
value[RIGHT(p)] = value[p];
value[p] = 0;
}
if (l > MID(left[p], right[p]))
{
return get(RIGHT(p), l);
}
else
{
return get(LEFT(p), l);
}
}
}tree;
int get_distance(bool vertical, int x, int y)
{
if (!vertical)
{
x = listx[x - 1];
y = listx[y - 1];
}
else
{
x = listy[x - 1];
y = listy[y - 1];
}
return abs(x - y);
}
void go(const vector<Object>& obj_array, bool vertical)
{
tree.build(1, 1, max(listx.size(), listy.size()) + 10);
for (vector<Object>::const_iterator it = obj_array.begin(); it != obj_array.end(); ++it)
{
if (it->type == WALL)
{
tree.set(1, it->y1, it->y2, it->id);
}
else
{
int p = tree.get(1, it->y1);
if (p)
{
int d = vertical ? min(get_distance(1, wall[p].y1, it->x), get_distance(1, wall[p].y2, it->x)) : min(get_distance(0, wall[p].x1, it->x), get_distance(0, wall[p].x2, it->x));
if (d < the_distance[it->id].d)
{
the_distance[it->id].d = d;
the_distance[it->id].id = p;
}
}
}
}
}
void fly_x()
{
vector<Object> obj_array;
for (int i = 1; i <= N; ++i)
{
obj_array.push_back(Object(wall[i].x1, wall[i].y1, wall[i].y2, i, WALL));
if (wall[i].x1 != wall[i].x2)
{
obj_array.push_back(Object(wall[i].x2, wall[i].y1, wall[i].y2, i, WALL));
}
}
for (int i = 1; i <= M; ++i)
{
obj_array.push_back(Object(bird[i].x, bird[i].y, 0, i, BIRD));
}
sort(obj_array.begin(), obj_array.end());
go(obj_array, false);
reverse(obj_array.begin(), obj_array.end());
go(obj_array, false);
}
void fly_y()
{
vector<Object> obj_array;
for (int i = 1; i <= N; ++i)
{
obj_array.push_back(Object(wall[i].y1, wall[i].x1, wall[i].x2, i, WALL));
if (wall[i].y1 != wall[i].y2)
{
obj_array.push_back(Object(wall[i].y2, wall[i].x1, wall[i].x2, i, WALL));
}
}
for (int i = 1; i <= M; ++i)
{
obj_array.push_back(Object(bird[i].y, bird[i].x, 0, i, BIRD));
}
sort(obj_array.begin(), obj_array.end());
go(obj_array, true);
reverse(obj_array.begin(), obj_array.end());
go(obj_array, true);
}
///////////////////////////SubMain//////////////////////////////////
int main(int argc, char *argv[])
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
scanf("%d%d", &N, &M);
for (int i = 1; i <= N; ++i)
{
scanf("%d%d%d%d", &wall[i].x1, &wall[i].y1, &wall[i].x2, &wall[i].y2);
if (wall[i].x1 > wall[i].x2)
{
swap(wall[i].x1, wall[i].x2);
}
if (wall[i].y1 > wall[i].y2)
{
swap(wall[i].y1, wall[i].y2);
}
listx.push_back(wall[i].x1);
listx.push_back(wall[i].x2);
listy.push_back(wall[i].y1);
listy.push_back(wall[i].y2);
}
for (int i = 1; i <= M; ++i)
{
scanf("%d%d", &bird[i].x, &bird[i].y);
listx.push_back(bird[i].x);
listy.push_back(bird[i].y);
}
sort(listx.begin(), listx.end());
listx.erase(unique(listx.begin(), listx.end()), listx.end());
sort(listy.begin(), listy.end());
listy.erase(unique(listy.begin(), listy.end()), listy.end());
for (int i = 1; i <= N; ++i)
{
wall[i].x1 = lower_bound(listx.begin(), listx.end(), wall[i].x1) - listx.begin() + 1;
wall[i].x2 = lower_bound(listx.begin(), listx.end(), wall[i].x2) - listx.begin() + 1;
wall[i].y1 = lower_bound(listy.begin(), listy.end(), wall[i].y1) - listy.begin() + 1;
wall[i].y2 = lower_bound(listy.begin(), listy.end(), wall[i].y2) - listy.begin() + 1;
}
for (int i = 1; i <= M; ++i)
{
bird[i].x = lower_bound(listx.begin(), listx.end(), bird[i].x) - listx.begin() + 1;
bird[i].y = lower_bound(listy.begin(), listy.end(), bird[i].y) - listy.begin() + 1;
}
fly_x();
fly_y();
for (int i = 1; i <= M; ++i)
{
++result[the_distance[i].id];
}
for (int i = 1; i <= N; ++i)
{
printf("%d\n", result[i]);
}
#ifndef ONLINE_JUDGE
fclose(stdin);
fclose(stdout);
system("out.txt");
#endif
return 0;
}
///////////////////////////End Sub//////////////////////////////////
| 13232546 | hankcs | 3470 | Accepted | 12768K | 3094MS | C++ | 5763B | 2014-08-02 20:05:06 |
码农场