把三角形拆成三条线段,以每个点为中心,极角排序,扫描线,用set维护线段,优先级为到中心点的距离,三角形不相交,相对顺序不变 ,查一下最近的线段是否挡住了,否则有贡献。
三角形的三条边实际上只有一条边有用。
#include<bits/stdc++.h>
#define il inline
#define rint register int
using namespace std;
typedef double db;
const int N=5005;
const db PI=acos(-1.0),eps=1e-8;
#define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
il int read() {
rint x=0;
char c=getchar();
for(; !isdigit(c); c=getchar());
for(; isdigit(c); c=getchar()) x=(x+(x<<2)<<1)+c-48;
return x;
}
il int sgn(db a) {
if(fabs(a)<eps) return 0;
return a<0?-1:1;
}
struct P {
db x,y,ag;
P(db x=0,db y=0):x(x),y(y) {}
il db dis() {
return sqrt(x*x+y*y);
}
il void get() {
ag=atan2(y,x);
} il void Read() {
x=read(),y=read();
}
il friend P operator +(P A,P B) {
return P(A.x+B.x,A.y+B.y);
}
il friend P operator -(P A,P B) {
return P(A.x-B.x,A.y-B.y);
}
il friend db operator *(P A,P B) {
return A.x*B.y-A.y*B.x;
}
il friend P operator *(P A,db B) {
return P(A.x*B,A.y*B);
}
il friend db dot(P A,P B) {
return A.x*B.x+A.y*B.y;
}
il bool operator <(const P &B) const {
return ag<B.ag;
}
il friend P I(P a1,P a2,P b1,P b2) {
db t=((b2-b1)*(a1-b1))/((a2-a1)*(b2-b1));
return a1+(a2-a1)*t;
}
} tt,_p[N],p[N],_t[N][3],t[N][3];
int tot,n,m,ans,pt,sg;
struct SS {
P u,v;
SS() {} SS(P u,P v):u(u),v(v) {}
bool operator <(const SS& B) const {
return I(u,v,P(0,0),tt).dis()<I(B.u,B.v,P(0,0),tt).dis();
}
} S[N];
multiset<SS> s;
multiset<SS>::iterator it[N];
struct E {
int f,idx;
db ag;
E() {} E(int f,int idx,db ag):f(f),idx(idx),ag(ag) {}
bool operator <(const E &B) const {
return sgn(ag-B.ag)==0?f>B.f:sgn(ag-B.ag)<0;
}
} ev[N];
il void Solve() {
tot=0;
for(rint i=1; i<=sg; ++i) ev[++tot]=E(1,i,S[i].u.ag),ev[++tot]=E(0,i,S[i].v.ag);
sort(p+1,p+pt+1);
sort(ev+1,ev+tot+1);
s.clear();
rint ret=0,j=1;
for(rint i=1; i<=pt; ++i) {
while(j<=tot &&(sgn(ev[j].ag-p[i].ag)<0 ||(sgn(ev[j].ag-p[i].ag)==0 && ev[j].f))) {
if(ev[j].f) tt=S[ev[j].idx].u,it[ev[j].idx]=s.insert(S[ev[j].idx]);
else tt=S[ev[j].idx].v,s.erase(it[ev[j].idx]);
++j;
}
if(s.empty()) {
++ret;
continue;
}
tt=p[i];
db dis=I((*s.begin()).u,(*s.begin()).v,0,tt).dis();
if(sgn(p[i].dis()-dis)<=0) ++ret;
}
ans+=ret;
}
int main() {
n=read(),m=read();
for(rint i=1; i<=n; ++i) _p[i].Read();
for(rint i=1; i<=m; ++i) for(rint j=0; j<3; ++j) _t[i][j].Read();
for(rint i=1; i<=n; ++i) {
pt=sg=0;
for(rint j=i+1; j<=n; ++j) (p[++pt]=_p[j]-_p[i]).get();
for(rint j=1; j<=m; ++j) {
for(rint k=0; k<3; ++k) t[j][k]=_t[j][k]-_p[i];
db ma=0;
P u,v;
for(rint k=0; k<3; ++k) {
db ag=dot(t[j][k],t[j][(k+1)%3])/t[j][k].dis()/t[j][(k+1)%3].dis();
ag=acos(ag);
if(ag>ma) ma=ag,u=t[j][k],v=t[j][(k+1)%3];
}
u.get();
v.get();
if(u.ag>v.ag) swap(u,v);
if(v.ag-u.ag<PI) S[++sg]=SS(u,v);
else {
P tmp=I(u,v,P(0,0),P(-1.0,0));
S[++sg]=SS(tmp,u),S[sg].u.ag=-PI,S[++sg]=SS(v,tmp),S[sg].v.ag=PI;
}
}
Solve();
}
return !printf("%d",ans);
}