题意:给你n条线段 ,求有多少个交点。
分析:第一直觉就是扫描线,然后发现要用树状数组维护前缀和。因为坐标大但是点数小,所以考虑离散化。
具体详见代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
typedef long long ll;
using namespace std;
const int maxn = 2e5 +20;
ll BIT[maxn],X[maxn],Y[maxn];
typedef pair<int ,int > P;
typedef pair<P,int> PI;
struct line
{
ll x,y,flag;
bool operator < (const line a)
{
if(y == a.y) return flag < a.flag;
return y<a.y;
}
}p[maxn];
void add(int x,ll v)
{
while(x<=maxn)
{
BIT[x] += v;
x += x&-x;
}
}
ll Sum(ll x)
{
ll ans = 0;
while(x)
{
ans += BIT[x];
x -= x&-x;
}
return ans;
}
int main(void)
{
// freopen("1006.in","r",stdin);
int n,T;
scanf("%d",&T);
while(T--)
{
memset(BIT,0,sizeof(BIT));
scanf("%d",&n);
ll x0,y0,x1,y1,kx = 0,ky = 0;
for(int i = 0;i < n;i ++)
{
scanf("%lld%lld%lld%lld",&x0,&y0,&x1,&y1);
if(x0 == x1)
{
if(y0 > y1) // 一定要加这一句话 不然会WA
swap(y0 , y1);
X[2*i] =x0;
Y[2*i] = y0;
Y[2*i+ 1] = y1;
p[2*i].x = x0;
p[2*i].y = y0;
p[2*i].flag = 1;
p[2*i + 1].x = x1;
X[2*i + 1] =x1;
p[2*i + 1].y = y1;
p[2*i + 1].flag = 4;
}
else
{
if(x0 > x1)
swap(x0 , x1);
p[2*i].x = x0;
X[2*i] =x0;
Y[2*i] = y0;
Y[2*i+ 1] = y1;
p[2*i].y = y0;
p[2*i].flag = 2;
p[2*i + 1].x = x1;
p[2*i + 1].y = y1;
X[2*i+1] =x1;
p[2*i + 1].flag = 3;
}
}
ll sum = 0;
sort(X,X + 2*n);
int k = unique(X,X+2*n) - X;
for(int i = 0;i<2*n;i++)
{
p[i].x = lower_bound(X , X +k,p[i].x) - X + 1;
}
sort(Y,Y + 2*n);
k = unique(Y,Y+2*n) - Y;
for(int i = 0;i<2*n;i++)
{
p[i].y = lower_bound(Y , Y +k,p[i].y) - Y + 1;
}
sort(p,p+2*n);
for(int i = 0;i<2*n;i++)
{
if(p[i].flag == 1 )
{
add(p[i].x,1);
}
else if(p[i].flag == 4) add(p[i].x,-1);
else if(p[i].flag == 2)
{
sum += - Sum(p[i].x - 1);
}
else sum += Sum(p[i].x);
}
printf("%lld\n",sum);
}
}
本文介绍了一种使用扫描线和树状数组计算多条线段交点数量的方法,并通过离散化处理坐标轴上的点,提供了完整的C++代码实现。
812

被折叠的 条评论
为什么被折叠?



