hdu 5862 Counting Intersections 坐标离散化+树状数组

题目大意:给你与坐标轴平行的线段,问相交点有多少。

我们将与x轴平行的线段分成两个点,左端点与右端点,与y坐标平行的线段取它的x坐标作为一个点,排序。那么一遍扫过去,遇到左端点,对应的y坐标++,遇到右端点对应的y坐标--,遇到第三种点,就是统计当前这个点对应y1,y2坐标之间出现过多少点。支持单点修改,区间求和,线段树树状数组都可以高效求解。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <map>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;

struct point{
	int x,y,yy,type;
	bool operator<(point t)const {
		if(x==t.x)return type<t.type;
		return x<t.x;
	}
}a[maxn*2];
int siz;
int pos[maxn][4];
int b[maxn*4];
int len;

int bit[maxn*4];
int sum(int i){
	int ans=0;
	while(i>0){
		ans+=bit[i];
		i-=i&-i;
	}
	return ans;
}
void add(int i,int x){
	while(i<maxn*4){
		bit[i]+=x;
		i+=i&-i;
	}
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		memset(bit,0,sizeof(bit));
		siz=len=0;
		int n;scanf("%d",&n);
		for(int i=0;i<n;i++){
			scanf("%d%d%d%d",&pos[i][0],&pos[i][1],&pos[i][2],&pos[i][3]);
			b[len++]=pos[i][0];b[len++]=pos[i][1];
			b[len++]=pos[i][2];b[len++]=pos[i][3];
		}
		sort(b,b+len);
		len=unique(b,b+len)-b;
		for(int i=0;i<n;i++){
			for(int j=0;j<4;j++){
				pos[i][j]=lower_bound(b,b+len,pos[i][j])-b+1;
			}
		}
		for(int i=0;i<n;i++){
			int x1,x2,y1,y2;
			x1=pos[i][0];y1=pos[i][1];
			x2=pos[i][2];y2=pos[i][3];
			if(y1==y2){
				if(x1>x2)swap(x1,x2);
				a[siz++]=point{x1,y1,0,-1};
				a[siz++]=point{x2,y1,0,1};
			}
			else{
				if(y1>y2)swap(y1,y2);
				a[siz++]=point{x1,y1,y2,0};
			}
		}
		sort(a,a+siz);
		long long ans=0;
		for(int i=0;i<siz;i++){
			if(a[i].type==0){
				ans+=sum(a[i].yy)-sum(a[i].y-1);
			}
			else{
				add(a[i].y,-a[i].type);
			}
		}
		printf("%I64d\n",ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值