hdu 5862 树状数组 + 扫描线 + 离散化

本文介绍了一种使用扫描线和树状数组计算多条线段交点数量的方法,并通过离散化处理坐标轴上的点,提供了完整的C++代码实现。

题意:给你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);
	}
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值