对每个关键点i,将每个三角形缩成一个线段(因为三角形不相交),然后把线段两端点 和其他关键点一起 以i为中心点 极角排序。
扫一圈。扫到一个关键点j时, 判断当前最靠近i的线段是否遮盖i到j的路径, 因为对同一个点i,线段之间的相对关系是不变的,所以可以用堆维护加线段删线段,
1 #include <bits/stdc++.h> 2 #define LL long long 3 using namespace std; 4 int T,n,m,p,q,k,t,x,y,z,ans,d[2005],e[1005]; 5 struct node{int x,y,d;}a[4005],b[4005],c[1005][3]; 6 LL operator *(node a,node b){return (LL)a.x*b.y-(LL)a.y*b.x;} 7 node operator -(node a,node b){return (node){a.x-b.x,a.y-b.y,a.d};} 8 bool hi(int u,int v){ // v是不是比u更接近中心点 9 LL x=(c[v][0]-c[u][0])*(c[u][2]-c[u][0]),y=(c[v][2]-c[u][0])*(c[u][2]-c[u][0]); 10 if (x>=0&&y>=0) return 0; if (x<=0&&y<=0) return 1; 11 return (c[u][0]-c[v][0])*(c[v][2]-c[v][0])>=0&&(c[u][2]-c[v][0])*(c[v][2]-c[v][0])>=0; 12 } 13 bool cmp(node u,node v){ LL x=(u-a[1])*(v-a[1]); if (!x) return u.d>v.d; else return x>0;} 14 void join(int x){ 15 int i=++T; 16 while (i>1&&hi(d[i>>1],x)) e[d[i]=d[i>>1]]=i,i>>=1; 17 d[i]=x; e[x]=i; 18 } 19 void del(int x){ 20 if (e[x]==T) {e[x]=d[T--]=0; return;} 21 int i=e[x]; e[x]=0; x=d[i]=d[T]; d[T--]=0; 22 while (i>1&&hi(d[i>>1],x)) e[d[i]=d[i>>1]]=i,i>>=1; 23 while (i<<1<=T&&hi(x,d[i<<1])||i<<1<T&&hi(x,d[i<<1^1])) 24 i<<1==T||hi(d[i<<1^1],d[i<<1])? 25 (e[d[i]=d[i<<1]]=i,i<<=1):(e[d[i]=d[i<<1^1]]=i,i=i<<1^1); 26 d[i]=x; e[x]=i; 27 } 28 int main(){ 29 scanf("%d%d",&n,&m); if (n==1) {puts("0"); return 0;} 30 for (t=1;t<=n;++t) scanf("%d%d",&a[t].x,&a[t].y); 31 for (int i=1;i<=m;++i) 32 for (int j=0;j<3;++j) 33 a[++t].d=i,scanf("%d%d",&a[t].x,&a[t].y),c[i][j]=a[t]; 34 t=n+m+m; 35 for (int i=1;i<=n;++i){ 36 while (T) e[d[T]]=0,d[T--]=0; 37 swap(a[i],a[1]); p=1; q=t+1; b[1]=a[1]; 38 for (int j=2;j<=n;++j) a[j].x<a[1].x?b[++p]=a[j]:b[--q]=a[j]; 39 for (int j=1;j<=m;++j){ 40 sort(c[j],c[j]+3,cmp); 41 c[j][0].x<a[1].x?b[++p]=c[j][0]:b[--q]=c[j][0]; 42 c[j][2].x<a[1].x?(b[++p]=c[j][2],b[p].d*=-1):(b[--q]=c[j][2],b[q].d*=-1); 43 } 44 if (2<=p) sort(b+2,b+p+1,cmp); 45 if (p<t)sort(b+p+1,b+t+1,cmp); 46 for (int j=1;j<=m;++j) 47 if ((c[j][0]-a[1])*(b[2]-a[1])>0&&(c[j][2]-a[1])*(b[2]-a[1])<=0) join(j); 48 for (int j=2;j<=t;++j) 49 if (!b[j].d){ 50 if (!T||(c[d[1]][2]-c[d[1]][0])*(b[j]-c[d[1]][0])>0) ++ans; 51 }else 52 if (b[j].d>0) join(b[j].d); else del(-b[j].d); 53 } 54 printf("%d",ans>>1); 55 return 0; 56 }
n^2*log*计算几何自带大常数。。。然而跑的还算挺快的