Hdu 5862 Counting Intersections(有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点+树状数组区间求和单点跟新)

时间:2022-07-12 13:15:43

传送门:Hdu 5862 Counting Intersections

题意:有n条线段,每一条线段都是平行于x轴或者y轴,问有多少个交点

分析:

基本的操作流程是:先将所有的线段按照横树坐标x按小的优先排序,注意是所有的线段 ;(这里是将线段都去掉只保留两个端点) 然后从左到右的顺序经行扫描,遇到横的线段,如果是左端点对应的 yi 便++ , 若是右端点对应的y1便--;  遇到竖直的线段,便统计区间[y1,y2] 的数 , 看到这了是不是有点东西了呢?

如果我是按照x排序的话,两线段若想相交,最基本的就是竖线的横坐标必须要大于等于横线的左端点,小于横线的右端点了吧,而且这条横线产生的贡献很明显就是在这横线的y坐标上呢?所有上面的流程都是依此与这个原理;(注意需要离散化哈)

#include<bits/stdc++.h>
using namespace std;
const int maxn=*;
int t[maxn];
struct node{
int x,l,r,flag;
}e[maxn];
int C[maxn],m; bool cmp(node u,node v){
if(u.x==v.x)
return u.flag>v.flag;
return u.x<v.x;
} void add(int x,int v){
while(x<=m) C[x]+=v,x+=(x&-x);
} int sum(int x){
int ret=;
while(x>)
ret+=C[x],x-=(x&-x);
return ret;
} int main(){
int T,n;
scanf("%d",&T);
while(T--){
scanf("%d",&n);
int x1,y1,x2,y2,Count=;
m=;
for(int i=;i<=n;i++){
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
if(x1>x2)
swap(x1,x2);
if(y1>y2)
swap(y1,y2);
t[++m]=y1,t[++m]=y2;
if(x1==x2)//竖直
e[++Count]=(node){x1,y1,y2,};
else{
e[++Count]=(node){x1,y1,y2,};
e[++Count]=(node){x2,y1,y2,-};
}
}
sort(t+,t+m+);
m=unique(t+,t+m+)-t-;
sort(e+,e+Count+,cmp);
for(int i=;i<=m;i++)
C[i]=;
long long ans=;
for(int i=;i<=Count;i++){
if(e[i].flag==){
int l=lower_bound(t+,t+m+,e[i].l)-t-,r=lower_bound(t+,t+m+,e[i].r)-t;
ans+=sum(r)-sum(l);
}
else{
int num=lower_bound(t+,t+m+,e[i].l)-t;
add(num,e[i].flag);
}
}
printf("%lld\n",ans);
}
return ;
}