题目:hdu 5862
题意:给定几个线段,求有多少个线段的交点,输入解释:第一行表示测试数据,第二行表示有多少条线段,第三行开始是每个线段的两点坐标
题解:树状数组+离散化(Y坐标太大,要压缩存储空间,采用离散化),先用map对y坐标进行离散化,再将与x轴平行的线段拆成两个点,一个是记录起点x坐标,一个记录末点x坐标+1(这样就可保证末点相交被记录进去,方便),与y轴平行的只要记录x坐标和两个y坐标即可,当成一个点,在将所有点以x坐标从小到大进行排列,排除掉了x坐标,就只要考虑y坐标即可,这样树状数组就可进行维护了,在树状数组中以Y坐标为高度,凡是高度在此中间的一定有交点,当然也要有个变量记录该点对应的线段是从与x轴平行的提取出来的还是y轴,具体见下代码
代码:
include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<algorithm>
#include<string>
#define MAX 100050
using namespace std;
typedef struct
{
int kind,x,y,y2;
}Segment;
Segment s[MAX*2];
int Y[MAX*2];
int c[MAX*2];
int num;
int ynum;
int mxan;
map<int,int> mp;
void init()
{
num=0;memset(c,0,sizeof(c));ynum=0;mp.clear();mxan=MAX*2;
}
void addSegment(int kind,int x,int y,int y2)
{
s[num].kind=kind;s[num].x=x;s[num].y=y;s[num].y2=y2;
num++;
}
bool compareY(int y1,int y2)
{
return y1<y2;
}
bool compareX(Segment z1,Segment z2)//以x坐标进行排序,当坐标相等时,要保证从平行x轴提取的点先进行考虑
{
if(z1.x==z2.x)
{
return z1.kind<z2.kind;
}
else
{
return z1.x<z2.x;
}
}
int lowbit(int x)
{
return x&(-x);
}
void add(int i,int v)
{
while(i<=mxan)
{
c[i]+=v;
i+=lowbit(i);
}
}
int sum(int i)
{
int ans=0;
while(i>0)
{
ans+=c[i];
i-=lowbit(i);
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
init();
scanf("%d",&n);
for(int i=0;i<n;i++)
{
int x,y,x1,y1;
scanf("%d %d %d %d",&x,&y,&x1,&y1);
if(x==x1)
{
if(y1>y) swap(y,y1);
addSegment(1,x,y,y1);
Y[ynum++]=y;
Y[ynum++]=y1;
}
else
{
if(x>x1) swap(x,x1);
addSegment(0,x,y,1);
addSegment(0,x1+1,y,-1);
Y[ynum++]=y;
}
}
sort(Y,Y+ynum,compareY);
int count1=1;
for(int i=0;i<ynum;i++)//离散化
{
if(!mp[Y[i]]) {mp[Y[i]]=count1++;}
}
mxan=count1+1;
sort(s,s+num,compareX);
long long sum2=0;
for(int i=0;i<num;i++)
{
if(s[i].kind==0)
{
add(mp[s[i].y],s[i].y2);
}
else
{
sum2+=sum(mp[s[i].y])-sum(mp[s[i].y2]-1);
}
}
printf("%lld\n",sum2);
}
return 0;
}