poj 3109 离散化+扫描线+树状数组

题意:

给一些坐标,求由这些坐标中的四个点组成的两条直线所相交的点有多少个。



解析:

扫描线+树状数组。

今天超级累,昨晚做cf做太晚了。。。

学习了扫描线的单点写法,有空了吧代码改成按Y扫描的熟悉熟悉。


UPDATE(15.8.7):

今天把整个过程模拟了一下,助于理解这种做法:

以样例为例:

4
0 2
2 0
-2 0
0 -2

算法依始,首先输入四个点的坐标,并且记录y的坐标值放入数组d,便于离散化:

nnode.xnode.yd
1022
2200
3-200
40-2-2

然后将node按x为主键值从小到大排序,d按y从小到大排序:

nnode.xnode.y
1-20
20-2
302
42

0

nd
12
20
30
4

-2

接着离散化node的y:

nnode.xnode.y
1-22
201
303
42

2

然后更新每一个node.y所对应的最左值lo,和最右值hi:

node.ylohi
100
2-22
300


接下来就可以根据以上的所有操作结合到每一个事件当中去,并且按照x和入事件出事件来排序了:

tag为1代表入事件,表示当前点进入计算区域,tag为-1代表出时间,表示当前点退出计算区域。

Even:

idxtag
1-21
201
301
20-1
30-1
12-1

接下来就是扫描线的过程:

对每一个不同的X,从小到大开始扫:

将所有x与扫描线X相等的点全找出来,然后更新当前求和区域up和down;

接着将所有坐标为X的事件,并且事件戳为入树的事件全部加入树状数组中维护。

然后求和,此时的计数即为当前线上所要求的点的个数。

求完和之后,将所有事件戳为出树的事件全部从树状数组中删去。


如样例:

首先扫到的是X = -2的点:

此时所有与X = -2相等的点只有一个,(-2,2)点。

所以更新完up和down,此时up和down都等于2;

所有事件中X = -2,并且入树戳为1的事件只有一个,此时将其加入树状数组。

然后求和,此时的计数即为当前线上所要求的点的个数。

求完和之后,此时没有存在X = -2的出树事件。

此时 ans = 1。


接下来扫第二条线:

重复上述过程,你会发现,当前up = 3, down = 1;

接着入树事件有 id = 2,x = 0,id = 3, x = 0,这两个,将其加入树状数组;

然后求down ~ up之间的和,发现此时和为3。(巧妙之处:之前的(-2, 2)点并未出树)。

然后出树的事件还是id = 2,x = 0,id = 3, x = 0,这两个,所以将其拿出树状数组。

此时 ans = 4。


接着是最后一条扫描线:

up = 2, down = 2。

没有入树事件,查找up~down之间的和为1。

接着有一个出树事件,就是最开始的时候加入的那个,出树,整个过程结束。

ans = 5。


换y的只是换了一个方向,差不离。


代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <map>
#include <climits>
#include <cassert>
#define LL long long
#define lson lo, mi, rt << 1
#define rson mi + 1, hi, rt << 1 | 1

using namespace std;
const int maxn = 100000 + 10;
const int inf = 0x3f3f3f3f;
const double eps = 1e-8;
const double pi = acos(-1.0);
const double ee = exp(1.0);

int c[maxn];
int n, m;

int X; //当前扫描线位置
struct Even
{
    int id, x;
    int tag;
    Even() {}
    Even(int _id, int _x, int _tag)
    {
        id = _id;
        x = _x;
        tag = _tag;
    }
    bool operator < (const Even& b) const
    {
        if (x == b.x)
            return tag > b.tag;
        return x < b.x;
    }
} even[maxn << 1];

int lowbit(int x)
{
    return x & -x;
}

void update(int x, int num)
{
    while (x <= m)
    {
        c[x] += num;
        x += lowbit(x);
    }
}

int query(int x)
{
    int res = 0;
    while (x)
    {
        res += c[x];
        x -= lowbit(x);
    }
    return res;
}

struct Node
{
    int x, y;
    bool operator < (const Node& b) const
    {
        if (x == b.x)
            return y < b.y;
        return x < b.x;
    }
} node[maxn];

int lo[maxn], hi[maxn];
int d[maxn];            //离散化数组

int main()
{
#ifdef LOCAL
    freopen("in.txt", "r", stdin);
#endif // LOCAL
//    while (~scanf("%d", &n))
//    {
    scanf("%d", &n);
    memset(c, 0, sizeof(c));
    for (int i = 1; i <= n; i++)
    {
        scanf("%d%d", &node[i].x, &node[i].y);
        d[i] = node[i].y;
    }
    sort(node + 1, node + 1 + n);
    //离散化
    sort(d + 1, d + 1 + n);
    m = unique(d + 1, d + 1 + n) - d - 1;
    for (int i = 1; i <= n; i++)
    {
        node[i].y = lower_bound(d + 1, d + 1 + m, node[i].y) - d;
    }
    memset(lo, inf, sizeof(lo));
    memset(hi, 0, sizeof(hi));
    for (int i = 1 ; i <= n ; ++ i)
    {
        if (lo[node[i].y] == inf)
            lo[node[i].y] = node[i].x;
        hi[node[i].y] = node[i].x;
    }
    for (int i = 1; i <= m; i++)
    {
        even[2 * i - 1] = Even(i, lo[i], 1);
        even[2 * i] = Even(i, hi[i], -1);
    }
    sort(even + 1, even + m + m + 1);
    LL ans = 0;
    int i = 1, j = 1;
    while (i <= n)
    {
        X = node[i].x;
        int up = -inf, down = inf;
        while (i <= n && node[i].x == X)
        {
            down = min(node[i].y, down);
            up = max(node[i].y, up);
            i++;
        }
        while (j <= m + m && even[j].x < X)
            j++;
        while (j <= m + m && even[j].x == X && even[j].tag == 1)
        {
            update(even[j].id, even[j].tag);
            j++;
        }
        ans += query(up) - query(down - 1);
        while (j <= m + m && even[j].x == X && even[j].tag == -1)
        {
            update(even[j].id, even[j].tag);
            j++;
        }
    }
    printf("%lld\n", ans);
//    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值