题目大意
给定n条水平或竖直的线段,统计所有线段的交点个数。 (n<=100000)
解题分析
首先将线段离散化。
然后将所有线段按照横坐标的顺序,按照先插入再查找再删除的顺序进行操作。
对于横线 如果是左端点,则将其纵坐标加1,右端点则减1,对于竖线直接求和就行了。
注意排序的时候优先处理竖线,因为有竖线刚好和横线左端点相交的情况
#include <cstdio>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <queue>
#include <map>
using namespace std;
#define L(i) i<<1
#define R(i) i<<1|1
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-4
#define maxn 100010
#define MOD 1000000007
int n;
struct node
{
int x,y1,y2;
int flag;
bool operator <(const node & a)const
{
return x < a.x || (x == a.x && flag > a.flag);
}
}cnt[maxn<<1];
map<int,int> mp;
int a[maxn<<1];
long long c[maxn<<1];
void update(int x,long long add)
{
while(x < (maxn<<1))
{
c[x] += add;
x += x & (-x);
}
}
long long get_sum(int x)
{
long long sum = 0;
while(x)
{
sum += c[x];
x -= x & (-x);
}
return sum;
}
int main()
{
int t,C = 1;
scanf("%d",&t);
while(t--)
{
memset(c,0,sizeof(c));
scanf("%d",&n);
int k = 0;
for(int i = 0; i < n; i++)
{
int x1,x2,y1,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1 == x2)
{
if(y1 > y2)
swap(y1,y2);
cnt[k].x = x1;
cnt[k].y1 = y1;
cnt[k].y2 = y2;
cnt[k++].flag = 0;
}
else
{
if(x1 > x2)
swap(x1,x2);
cnt[k].x = x1;
cnt[k].y1 = y1;
cnt[k].y2 = y2;
cnt[k++].flag = 1;
cnt[k].x = x2+1;
cnt[k].y1 = y1;
cnt[k].y2 = y2;
cnt[k++].flag = 2;
}
a[2*i] = y1;
a[2*i+1] = y2;
}
sort(a,a+2*n);
mp.clear();
int len = unique(a,a+2*n) - a;
for(int i = 1; i <= len; i++)
mp[a[i-1]] = i;
sort(cnt,cnt+k);
long long ans = 0;
for(int i = 0; i < k; i++)
{
if(!cnt[i].flag)
ans += get_sum(mp[cnt[i].y2]) - get_sum(mp[cnt[i].y1]-1);
else if(cnt[i].flag == 1)
update(mp[cnt[i].y1],1);
else
update(mp[cnt[i].y1],-1);
}
printf("%lld\n",ans);
}
return 0;
}