[CQOI2017]小Q的草稿

传送门

把三角形拆成三条线段,以每个点为中心,极角排序,扫描线,用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);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值