hdu5862 树状数组+扫描线+离散化
hdu5862 Counting Intersections
传送门
题意
有\(n\)条与\(x\)轴或者\(y\)轴平行的线段,计算交点的个数
\(1\leq n\leq 100000\),端点坐标的绝对值不超过\(1e9\)
题解
按照纵坐标从小到大扫描,竖线两个端点按照两个元素存储,横线由于只有一个纵坐标,按照一个元素存储,同时通过\(id\)表示是横线还是竖线的端点
树状数组统计与每一条横线相交的交点个数,扫描到竖线的下端点时,将这条竖线的横坐标对应的树状数组元素加一,表示加入,扫描到下端点时,同样的横坐标对应的树状数组元素值减一,表示删除
扫描到横线时,如果左右端点分别为\(l\)和\(r\),则树状数组统计与这条横线相交的交点个数为\(query(r)-query(l-1)\)
\(ps:\)由于坐标值可能较大,而点数不超过\(1e5\),所以横坐标离散化之后再用树状数组统计
#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cstring>
#include<string>
#include<sstream>
#include<cmath>
#include<ctime>
#include<algorithm>
#define LL long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define eps 1e-6
#define lowbit(x) x&(-x)
using namespace std;
const int maxn=100010;
int T,n,ax[2*maxn],bit[2*maxn];
struct node{
int x1,x2,y,id;
bool operator < (const node t)const{
if(y!=t.y) return y<t.y;
return id>t.id;
}
}p[2*maxn];
void change(int n,int x,int v){
for(int i=x;i<=n;i+=lowbit(i)){
bit[i]+=v;
}
}
int query(int x){
int s=0;
for(int i=x;i>0;i-=lowbit(i)){
s+=bit[i];
}
return s;
}
int main(){
scanf("%d",&T);
while(T--){
memset(bit,0,sizeof(bit));
scanf("%d",&n);
int pi=0;
int xi=0;
for(int i=0;i<n;i++){
int x1,x2,y1,y2;
scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
ax[xi++]=x1;
ax[xi++]=x2;
if(x1>x2) swap(x1,x2);
if(y1>y2) swap(y1,y2);
if(x1==x2){
p[pi].x1=x1;
p[pi].y=y1;
p[pi++].id=1;
p[pi].x1=x2;
p[pi].y=y2;
p[pi++].id=-1;
}
else{
p[pi].x1=x1;
p[pi].x2=x2;
p[pi].y=y1;
p[pi++].id=0;
}
}
sort(p,p+pi);
sort(ax,ax+xi);
int len=unique(ax,ax+xi)-ax;
LL ans=0;
for(int i=0;i<pi;i++){
if(p[i].id==0){
int l=lower_bound(ax,ax+len,p[i].x1)-ax+1;
int r=lower_bound(ax,ax+len,p[i].x2)-ax+1;
ans+=query(r)-query(l-1);
}
else{
int pos=lower_bound(ax,ax+len,p[i].x1)-ax+1;
change(len,pos,p[i].id);
}
}
printf("%lld\n",ans);
}
return 0;
}