POJ 3470 Walls 桶上分树

一、题目大意

我们有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过了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值