一、题目大意
我们有n面围墙,这些围墙高度无限!从一架飞机向下看,就像一条条线段一般!我们做些实验,有m只小鸟,它们会不断的飞直到碰撞围墙!确保每一只小鸟放下来,它一定会撞到围墙,而且它会朝着最快撞到围墙的方向去飞,题目保证每只小鸟的四个方向里,只有一个方向是最近的
然后题目最后需要我们输出,每一面墙被小鸟撞过的次数
题目中的墙都是与坐标轴垂直的,一定为竖直方向,或水平方向。
n最大可以达到50000,m最大也可以达到50000,限定时间6秒钟!
题目不会一开始就把小鸟放在墙上
二、解题思路
思考这样的一个问题,我们可以对墙分开考虑,这里我假设 x1<=x2 ,y1 <= y2
情况1、对于水平方向的墙,x1 != x2,y1 == y2,那么根据小鸟的位置 x y,当x1<= x <=x2时,这面墙是一定可以够得到的!然后到这面墙的距离就是 |y1 - y|
情况2、对于竖直方向的墙,x1 == x2,y1 != y2,那么根据愤怒的小鸟的位置,当 y1 <= y <= y2时,这面墙也一定够的到吧!距离是 |x1 - x|
然后水平和墙和竖直的墙都考虑到了,那么还可能存在这面墙就与 小鸟在同一行或者同一列的情况。
情况3、与小鸟在用一列的墙 x1 == x2 == x,然后 y2 < y 或者 y1 > y,这种的话,对于 y2 < y的,y - y2就是它的距离,对于 y1 > y 的,y1 - y 就是它的距离。
情况4、与小鸟在同一行的墙,y1 == y2 == x,然后 x2 < x 或者 x1 > x,这种的话,对于x2 < x的墙,x - x2是它的距离,对于x1 > x的墙,x1 - x是它的距离。
然后有i可能存在一只小鸟撞多个墙的情况,但是我觉得最多只撞的到2面墙,从题目大意上看,墙的高度无限,是不会有重合的,唯一的重合就是竖直与水平相交!而小鸟撞多个墙的情况,就是它撞到了这个交点,所以撞到2面墙,见下图!
针对情况1,我们把x1 != x2的墙都记录下来,根据x1排序放到row数组,然后按2048的大小进行分桶,每个桶内按 x2排序,然后针对每个桶的数组,建立一颗线段树(归并树)树上的每个节点按照 y1 排序,针对每次 x y,首先二分 row数组,找到 x1<=x的区间,确定涉及到的桶,在桶内二分找到 x2 >= x的区间,然后去线段树上查出这些区间里最接近 y 的 y1,并用abs(y - y1)更新结果。对于桶外的元素(不超过2048)那就去row数组一个个判断了,如果 x2>=x那么用abs(y - y1)更新结果即可。
针对情况2,我们把y1 != y2的墙都记录下来,根据y1排序放在col数组,然后按2048的大小进行分桶,每个桶内按 y2排序。针对每个桶的数组,建立一颗线段树(归并树)树上每个节点按照y1排序,针对每次x y,首先二分col数组,找到y1<=y的区间,确定涉及到的桶,在桶内二分找到y2>=y的区间,然后去线段树上查出这些区间里最接近x的x1,并用abs(x - x1)更新结果。对于桶外的元素(不超过2048)那就去col数组一个个判断了,如果y2>=y那就用abs(x - x1)更新结果即可。
针对情况3,我们可以把x1 == x2的墙,放在数组里,然后优先根据 x1 排序,对x1相同的,根据 y1 排序,这样我们根据小鸟的位置 x y ,只需要把它传进去数组二分得到idx,然后判断idx的位置 x1是不是与 x相等,是的话,距离是 y1 - y(lower_bound得到的是第一个不小于的到idx,则idx要么x1==x且y1>=y,要么x1>x),判断下这个距离是不是最近的,然后idx--,再判断idx的位置是不是x1与x相等,是的话,用 y - y2更新结果
针对情况4,我们可以把y1 == y2的墙,放在数组里,优先根据 y1 排序,对于 y1 相同的,根据 x1 排序,然后也是把 x 和 y传进来,去二分得到idx,判断 idx位置的y1==y?,若相等,则 判断距离 x1 - x更新结果,再判断idx-1位置的y1==y?,若相等,用 x - x2更新结果。
需要注意的一点是,我在使用vector建树的时候超时了,最好不用vector,用指针。
三、桶上分树代码
#include <iostream>
#include <algorithm>
using namespace std;
struct Same
{
int _same, _other, _idx;
Same(int _same = 0, int _other = 0, int _idx = 0) : _same(_same), _other(_other), _idx(_idx) {}
};
bool compareSame(const Same &a, const Same &b)
{
return a._same != b._same ? a._same < b._same : a._other < b._other;
}
Same sameX[50009], sameY[50009];
int sameXSize, sameYSize;
const int B = 2048;
typedef pair<int, int> P;
int rowSize, colSize;
P row[50009], col[50009], bktR[27][2057], bktC[27][2057];
// P datR[27][100][100], datC[27][100][100];
P **datR[27], **datC[27];
int x[50009], y[50009], x1[50009], x2[50009], y1[50009], y2[50009], n, m;
void swapIfNeed(int i)
{
int tmp;
if (x1[i] > x2[i])
{
tmp = x1[i];
x1[i] = x2[i];
x2[i] = tmp;
}
if (y1[i] > y2[i])
{
tmp = y1[i];
y1[i] = y2[i];
y2[i] = tmp;
}
}
void input()
{
rowSize = 0, colSize = 0, sameXSize = 0, sameYSize = 0;
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++)
{
scanf("%d%d%d%d", &x1[i], &y1[i], &x2[i], &y2[i]);
swapIfNeed(i);
if (x1[i] != x2[i])
{
row[rowSize].first = x1[i];
row[rowSize].second = i;
rowSize++;
}
if (y1[i] != y2[i])
{
col[colSize].first = y1[i];
col[colSize].second = i;
colSize++;
}
if (x1[i] == x2[i])
{
sameX[sameXSize]._same = x1[i];
sameX[sameXSize]._other = y1[i];
sameX[sameXSize]._idx = i;
sameXSize++;
}
if (y1[i] == y2[i])
{
sameY[sameYSize]._same = y1[i];
sameY[sameYSize]._other = x1[i];
sameY[sameYSize]._idx = i;
sameYSize++;
}
}
for (int i = 0; i < m; i++)
{
scanf("%d%d", &x[i], &y[i]);
}
}
void sortAll()
{
sort(row, row + rowSize);
sort(col, col + colSize);
sort(sameX, sameX + sameXSize, compareSame);
sort(sameY, sameY + sameYSize, compareSame);
}
void build(int idx, int i, int l, int r, bool isR)
{
if (r - l == 1)
{
if (isR)
{
datR[idx][i] = new P[1];
datR[idx][i][0].first = y1[bktR[idx][l].second];
datR[idx][i][0].second = bktR[idx][l].second;
}
else
{
datC[idx][i] = new P[1];
datC[idx][i][0].first = x1[bktC[idx][l].second];
datC[idx][i][0].second = bktC[idx][l].second;
}
}
else
{
int lch = i * 2 + 1;
int rch = i * 2 + 2;
int mid = (l + r) / 2;
build(idx, lch, l, mid, isR);
build(idx, rch, mid, r, isR);
if (isR)
{
datR[idx][i] = new P[r - l];
merge(datR[idx][lch], datR[idx][lch] + (mid - l), datR[idx][rch], datR[idx][rch] + (r - mid), datR[idx][i]);
}
else
{
datC[idx][i] = new P[r - l];
merge(datC[idx][lch], datC[idx][lch] + (mid - l), datC[idx][rch], datC[idx][rch] + (r - mid), datC[idx][i]);
}
}
}
int calcSize(int _size)
{
int size = 1;
while (size < _size)
{
size = size * 2;
}
return size * 2 - 1;
}
void buckedMethod()
{
for (int i = 0; i < rowSize; i++)
{
bktR[i / B][i - ((i / B) * B)].first = x2[row[i].second];
bktR[i / B][i - ((i / B) * B)].second = row[i].second;
}
for (int i = 0; i < rowSize; i = i + B)
{
int bucketR = i + B;
bucketR = (bucketR > rowSize ? rowSize : bucketR);
sort(bktR[i / B], bktR[i / B] + (bucketR - i));
int size = calcSize(bucketR - i);
datR[i / B] = new P *[size];
build(i / B, 0, 0, (bucketR - i), true);
}
for (int i = 0; i < colSize; i++)
{
bktC[i / B][i - ((i / B) * B)].first = y2[col[i].second];
bktC[i / B][i - ((i / B) * B)].second = col[i].second;
}
for (int i = 0; i < colSize; i = i + B)
{
int bucketR = i + B;
bucketR = (bucketR > colSize ? colSize : bucketR);
sort(bktC[i / B], bktC[i / B] + (bucketR - i));
int size = calcSize(bucketR - i);
datC[i / B] = new P *[size];
build(i / B, 0, 0, (bucketR - i), false);
}
}
int ansIdx[50009][10], ans[50009], ansLen[50009], ansDist[50009], _current;
void updateAns(int dist, int idx)
{
if (ansDist[_current] == 0 || ansDist[_current] == dist)
{
ansIdx[_current][ansLen[_current]] = idx;
ansLen[_current] = ansLen[_current] + 1;
ansDist[_current] = dist;
}
if (ansDist[_current] > dist)
{
ansLen[_current] = 0;
ansIdx[_current][ansLen[_current]] = idx;
ansLen[_current] = ansLen[_current] + 1;
ansDist[_current] = dist;
}
}
void handleSame(Same current, int size, bool isR)
{
if (size <= 0)
{
return;
}
int idx;
if (isR)
{
idx = lower_bound(sameX, sameX + size, current, compareSame) - sameX;
}
else
{
idx = lower_bound(sameY, sameY + size, current, compareSame) - sameY;
}
if (isR)
{
if (idx < size && sameX[idx]._same == current._same)
{
updateAns(sameX[idx]._other - current._other, sameX[idx]._idx);
}
idx--;
if (idx >= 0 && sameX[idx]._same == current._same)
{
updateAns(current._other - y2[sameX[idx]._idx], sameX[idx]._idx);
}
}
else
{
if (idx < size && sameY[idx]._same == current._same)
{
updateAns(sameY[idx]._other - current._other, sameY[idx]._idx);
}
idx--;
if (idx >= 0 && sameY[idx]._same == current._same)
{
updateAns(current._other - x2[sameY[idx]._idx], sameY[idx]._idx);
}
}
}
void handleTreeNode(P current, int bkt, int tree, int size, bool isR)
{
int idx;
if (isR)
{
idx = lower_bound(datR[bkt][tree], datR[bkt][tree] + size, current) - datR[bkt][tree];
}
else
{
idx = lower_bound(datC[bkt][tree], datC[bkt][tree] + size, current) - datC[bkt][tree];
}
for (int i = idx - 1; i <= idx; i++)
{
if (i >= 0 && i < size)
{
if (isR)
{
updateAns(abs(datR[bkt][tree][i].first - current.first), datR[bkt][tree][i].second);
}
else
{
updateAns(abs(datC[bkt][tree][i].first - current.first), datC[bkt][tree][i].second);
}
}
}
}
void queryTree(P current, int bkt, int _l, int _r, int i, int l, int r, bool isR)
{
if (_l >= r || _r <= l)
{
}
else if (l >= _l && r <= _r)
{
handleTreeNode(current, bkt, i, r - l, isR);
}
else
{
queryTree(current, bkt, _l, _r, i * 2 + 1, l, (l + r) / 2, isR);
queryTree(current, bkt, _l, _r, i * 2 + 2, (l + r) / 2, r, isR);
}
}
void handleBucket(int size, int first, int second, bool isR)
{
if (size <= 0)
{
return;
}
int limit;
if (isR)
{
limit = upper_bound(row, row + size, P(first, 0x3f3f3f3f)) - row;
}
else
{
limit = upper_bound(col, col + size, P(first, 0x3f3f3f3f)) - col;
}
if (limit <= 0)
{
return;
}
for (int i = 0; i < size; i = i + B)
{
int bucketL = i;
int bucketR = i + B;
bucketR = (bucketR > size ? size : bucketR);
if (bucketL >= limit)
{
break;
}
if (bucketR <= limit)
{
int idx;
if (isR)
{
idx = lower_bound(bktR[i / B], bktR[i / B] + (bucketR - bucketL), P(first, -0x3f3f3f3f)) - bktR[i / B];
}
else
{
idx = lower_bound(bktC[i / B], bktC[i / B] + (bucketR - bucketL), P(first, -0x3f3f3f3f)) - bktC[i / B];
}
if (idx < (bucketR - bucketL))
{
queryTree(P(second, -0x3f3f3f3f), i / B, idx, (bucketR - bucketL), 0, 0, (bucketR - bucketL), isR);
}
continue;
}
for (int j = bucketL; j < limit; j++)
{
int need;
if (isR)
{
need = x2[row[j].second];
}
else
{
need = y2[col[j].second];
}
if (need >= first)
{
if (isR)
{
updateAns(abs(y1[row[j].second] - second), row[j].second);
}
else
{
updateAns(abs(x1[col[j].second] - second), col[j].second);
}
}
}
}
}
void solve()
{
for (int i = 0; i < m; i++)
{
_current = i;
handleBucket(rowSize, x[i], y[i], true);
handleSame(Same(x[i], y[i], -0x3f3f3f3f), sameXSize, true);
handleBucket(colSize, y[i], x[i], false);
handleSame(Same(y[i], x[i], -0x3f3f3f3f), sameYSize, false);
}
}
void putAns()
{
for (int i = 0; i < m; i++)
{
for (int j = 0; j < ansLen[i]; j++)
{
ans[ansIdx[i][j]] = ans[ansIdx[i][j]] + 1;
}
}
for (int i = 0; i < n; i++)
{
printf("%d\n", ans[i]);
}
}
int main()
{
input();
sortAll();
buckedMethod();
solve();
putAns();
return 0;
}
四、效率
题目限时6000ms,差不多用了4600ms过了。