题意:
给一些坐标,求由这些坐标中的四个点组成的两条直线所相交的点有多少个。
解析:
扫描线+树状数组。
今天超级累,昨晚做cf做太晚了。。。
学习了扫描线的单点写法,有空了吧代码改成按Y扫描的熟悉熟悉。
UPDATE(15.8.7):
今天把整个过程模拟了一下,助于理解这种做法:
以样例为例:
4 0 2 2 0 -2 0 0 -2
算法依始,首先输入四个点的坐标,并且记录y的坐标值放入数组d,便于离散化:
n | node.x | node.y | d |
1 | 0 | 2 | 2 |
2 | 2 | 0 | 0 |
3 | -2 | 0 | 0 |
4 | 0 | -2 | -2 |
然后将node按x为主键值从小到大排序,d按y从小到大排序:
n | node.x | node.y |
1 | -2 | 0 |
2 | 0 | -2 |
3 | 0 | 2 |
4 | 2 | 0 |
n | d |
1 | 2 |
2 | 0 |
3 | 0 |
4 | -2 |
接着离散化node的y:
n | node.x | node.y |
1 | -2 | 2 |
2 | 0 | 1 |
3 | 0 | 3 |
4 | 2 | 2 |
然后更新每一个node.y所对应的最左值lo,和最右值hi:
node.y | lo | hi |
1 | 0 | 0 |
2 | -2 | 2 |
3 | 0 | 0 |
接下来就可以根据以上的所有操作结合到每一个事件当中去,并且按照x和入事件出事件来排序了:
tag为1代表入事件,表示当前点进入计算区域,tag为-1代表出时间,表示当前点退出计算区域。
Even:
id | x | tag |
1 | -2 | 1 |
2 | 0 | 1 |
3 | 0 | 1 |
2 | 0 | -1 |
3 | 0 | -1 |
1 | 2 | -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;
}