题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=5862
题意:给你n条平行x轴或y轴的直线,求直线之间交点的个数
分析:
首先按照x轴排序,这样扫描竖线时就不用考虑 左端点在竖线右边的横线
因为结果只依赖于左端点在竖线左边的横线,所以用树状数组保存及更新(当有左端点进入时+1,右端点-1)
#include <cstdio>
#include <iostream>
#include <map>
#include <algorithm>
#include <cstring>
using namespace std;
#define maxn 200050
typedef long long int LL;
int T , n;
struct Node//type 0 代表横向,1代表竖线
{
int x,y,y1,type;//当为横线时 y1 = 1 代表左端点 ,y1 = -1 代表右端点
bool operator < (const Node & R)const{
return (x == R.x ? type < R.type : x < R.x);
}
}node[maxn];
int ncnt;
int yi[maxn];
int ycnt;
int Maxn;
int bi[maxn];
void add(int n,int add)
{
for(int i = n ; i <= Maxn ; i += i&(-i))
bi[i] += add;
}
LL getNum(int n)
{
LL res = 0;
for(int i = n ; i >= 1; i -= i&(-i))
res += bi[i];
return res;
}
void init()
{
ncnt = ycnt = 0;
memset(bi,0,sizeof(bi));
}
int main()
{
cin >> T;
while( T-- )
{
init();
cin >> n;
for(int i = 0 ; i < n ; ++i)
{
int x1,y1,x2,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
if( x1 == x2 )
{
if( y1 > y2 )swap(y1,y2);
yi[ycnt++] = y1;
yi[ycnt++] = y2;
node[ncnt++] = {x1,y1,y2,1};
}
else
{
if( x1 > x2 )swap(x1,x2);
yi[ycnt++] = y1;
node[ncnt++] = {x1,y1,1,0};
node[ncnt++] = {x2+1,y2,-1,0};//因为在x2点时 还可以相交
}
}
sort(yi,yi+ycnt);
int acl = 0;
map<int,int>mp;
for (int i = 0; i < ycnt; i++){
if (!mp[yi[i]]) mp[yi[i]] = ++acl;
}
Maxn = acl;
sort(node,node+ncnt);
LL ans = 0 ;
for(int i = 0 ; i < ncnt ; ++i)
{
Node &e = node[i];
if( e.type )//竖线
{
ans += getNum(mp[e.y1]) - getNum(mp[e.y]-1);
}
else
{
add( mp[e.y] , e.y1 );
}
}
cout << ans << endl;
}
}