题意
有n条线段,且都平行于坐标轴。对于每条线段,给出两个端点的坐标。问一共有多少个线段的交点。
分析
最最简单的扫描法了。用线段树或者树状数组都可以。
由题目可知,线段只有两种,要么平行于x轴要么平行于y轴。而交点只能是两个不平行的线段产生的。
所有我们以一条平行于x轴的线为扫描线,从下向上扫。先把横坐标进行离散化,然后把平行于y轴的线段拆成上下两个端点。当扫到下端点的时候就在它横坐标+1,当扫到上端点的时候,就在它横坐标-1.对于每一条平行于x轴的线,则将左右端点内的值相加。就酱~
这里一个小细节是,如果是下端点,则先更新,再计算。如果是上端点,则先计算再更新。
讲真,这个题让我很难受,本来以为很快就能解决的题结果TLE了一晚上,刚刚才发现,是数组开小了(;´??Д??`)
线段树
1 #include <cstdio> 2 #include <algorithm> 3 #include <iostream> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 typedef long long LL; 8 const int maxn=100000+100; 9 struct Point { 10 int j;//1,0,-1 11 int x,h; 12 int l,r; 13 bool operator <(const Point &rhs)const { 14 return h<rhs.h||(h==rhs.h&&j>rhs.j); 15 } 16 }seg[2*maxn]; 17 int T,n,x1,y1,x2,y2,sz,sk; 18 LL ans; 19 int v[2*maxn],sumv[8*maxn]; 20 int vv,x; 21 void update(int o,int L,int R){ 22 if(L==R){ 23 sumv[o]+=vv; 24 return ; 25 } 26 int M=L+(R-L)/2; 27 if(x<=M) update(2*o,L,M); 28 if(x>M) update(2*o+1,M+1,R); 29 sumv[o]=sumv[2*o]+sumv[2*o+1]; 30 return ; 31 } 32 int ql,qr; 33 int query(int o,int L,int R){ 34 if(ql<=L&&qr>=R){ 35 return sumv[o]; 36 } 37 int res=0; 38 int M=L+(R-L)/2; 39 if(ql<=M) 40 res+=query(2*o,L,M); 41 if(qr>M) 42 res+=query(2*o+1,M+1,R); 43 return res; 44 } 45 int main(){ 46 scanf("%d",&T); 47 for(int t=1;t<=T;t++){ 48 sz=sk=ans=0; 49 scanf("%d",&n); 50 for(int i=1;i<=n;i++){ 51 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 52 if(x1>x2||y1>y2){ 53 swap(x1,x2); 54 swap(y1,y2); 55 } 56 if(x1==x2){ 57 seg[++sz].x=x1,seg[sz].h=y1,seg[sz].j=1; 58 seg[++sz].x=x1,seg[sz].h=y2,seg[sz].j=-1; 59 v[++sk]=x1; 60 }else if(y1==y2){ 61 seg[++sz].h=y1,seg[sz].l=x1,seg[sz].r=x2,seg[sz].j=0; 62 v[++sk]=x1,v[++sk]=x2; 63 } 64 } 65 sort(seg+1,seg+1+sz); 66 sort(v+1,v+1+sk); 67 int N=unique(v+1,v+1+sk)-v-1; 68 memset(sumv,0,sizeof(sumv)); 69 for(int i=1;i<=sz;i++){ 70 if(seg[i].j==0){ 71 ql=lower_bound(v+1,v+1+N,seg[i].l)-v; 72 qr=lower_bound(v+1,v+1+N,seg[i].r)-v; 73 ans+=query(1,1,N); 74 }else{ 75 vv=seg[i].j;x=lower_bound(v+1,v+1+N,seg[i].x)-v; 76 update(1,1,N); 77 } 78 } 79 printf("%lld\n",ans); 80 } 81 return 0; 82 }
树状数组
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <iostream> 5 6 using namespace std; 7 8 const int maxn=100000+100; 9 struct Point { 10 int j;//1,0,-1 11 int x,h; 12 int l,r; 13 bool operator <(const Point &rhs)const { 14 return h<rhs.h||(h==rhs.h&&j>rhs.j); 15 } 16 }seg[2*maxn]; 17 int T,n,x1,y1,x2,y2,sz,sk,N; 18 long long ans,C[2*maxn]; 19 int v[2*maxn]; 20 int lowbit(int x){ 21 return x&(-x); 22 } 23 void add(int x,int d){ 24 while(x<=N){ 25 C[x]+=d; 26 x+=lowbit(x); 27 } 28 } 29 long long sum(int x){ 30 long long res=0; 31 while(x>0){ 32 res+=C[x]; 33 x-=lowbit(x); 34 } 35 return res; 36 } 37 int main(){ 38 scanf("%d",&T); 39 for(int t=1;t<=T;t++){ 40 sz=sk=ans=0; 41 scanf("%d",&n); 42 for(int i=1;i<=n;i++){ 43 scanf("%d%d%d%d",&x1,&y1,&x2,&y2); 44 if(x1>x2||y1>y2){ 45 swap(x1,x2); 46 swap(y1,y2); 47 } 48 if(x1==x2){ 49 seg[++sz].x=x1,seg[sz].h=y1,seg[sz].j=1; 50 seg[++sz].x=x1,seg[sz].h=y2,seg[sz].j=-1; 51 v[++sk]=x1; 52 }else if(y1==y2){ 53 seg[++sz].h=y1,seg[sz].l=x1,seg[sz].r=x2,seg[sz].j=0; 54 v[++sk]=x1,v[++sk]=x2; 55 } 56 } 57 sort(seg+1,seg+1+sz); 58 sort(v+1,v+1+sk); 59 N=unique(v+1,v+1+sk)-v-1; 60 61 for(int i=1;i<=sz;i++){ 62 if(seg[i].j==0){ 63 int l=lower_bound(v+1,v+1+N,seg[i].l)-v; 64 int r=lower_bound(v+1,v+1+N,seg[i].r)-v; 65 // cout<<l<<" "<<r<<endl; 66 ans+=sum(r)-sum(l-1); 67 } 68 else{ 69 int x=lower_bound(v+1,v+1+N,seg[i].x)-v; 70 // cout<<x<<" "<<seg[i].j<<endl; 71 add(x,seg[i].j); 72 } 73 } 74 printf("%lld\n",ans); 75 } 76 return 0; 77 }
原文地址:https://www.cnblogs.com/LQLlulu/p/9040342.html
时间: 2024-10-11 03:34:08