题意:
给出一系列与x或者y平行的线段,计算一共有多少交点
分析:
对线段进行排序,然后对于平行于y轴的线段在线段树上进行更新操作,下端点来的时候插入线段树,上端点来的时候从线段树中删除(+1 -1 即可),平行于x轴的线段进行区间查询求和即可。
PS:正确排序很重要(对y排序>下端点>平行于x轴>上端点),而且还要离散化
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
struct point{
int x,y;
point(){}
point(int x,int y):x(x),y(y){}
} ;
struct segment{
point a,b;
int c; //用于排序,bottom>(left||right)>top
segment(point a,point b,int c):a(a),b(b),c(c){}
bool operator <(const segment & p){
if(a.y!=p.a.y) return a.y<p.a.y;
return c!=p.c?c<p.c:a.x<p.a.x;
}
};
vector<segment> v;
int x[maxn*2];
int tree[maxn<<2];
void up(int p){
tree[p]=tree[p<<1]+tree[p<<1|1];
}
void modify(int p,int l,int r,int x,int v){
if(l==r){
tree[p]+=v;
return ;
}
int mid=l+r>>1;
if(x<=mid){
modify(p<<1,l,mid,x,v);
}else{
modify(p<<1|1,mid+1,r,x,v);
}
up(p);
}
int query(int p,int l,int r,int x,int y){
if(x<=l&&r<=y){
return tree[p];
}
int mid=l+r>>1;
int res=0;
if(x<=mid){
res+=query(p<<1,l,mid,x,y);
}
if(y>mid){
res+=query(p<<1|1,mid+1,r,x,y);
}
return res;
}
int main(){
int n;
scanf("%d",&n);
int len=1;
for(int i=0;i<n;i++){
point a,b;
scanf("%d%d%d%d",&a.x,&a.y,&b.x,&b.y);
if(a.x!=b.x){
if(a.x>b.x) swap(a,b);
x[len++]=a.x;
x[len++]=b.x;
v.push_back(segment(a,b,2));
}else{
if(a.y>b.y) swap(a,b);
x[len++]=a.x;
v.push_back(segment(a,a,1));
v.push_back(segment(b,b,3));
}
}
len--;
sort(x+1,x+len+1);
len=unique(x+1,x+len+1)-(x+1);
sort(v.begin(),v.end());
int vsize=v.size();
int ans=0;
for(int i=0;i<vsize;i++){
if(v[i].a.x==v[i].b.x){
int id=lower_bound(x+1,x+len+1,v[i].a.x)-x;
int c=v[i].c==3?-1:1;
modify(1,1,len,id,c);
}else{
int id1=lower_bound(x+1,x+len+1,v[i].a.x)-x;
int id2=lower_bound(x+1,x+len+1,v[i].b.x)-x;
ans+=query(1,1,len,id1,id2);
}
}
printf("%d\n",ans);
return 0;
}