码迷,mamicode.com
首页 > 其他好文 > 详细

[TopCoder12693]EnclosingTriangle

时间:2021-04-07 10:59:47      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:复杂度   puts   operator   its   break   vat   std   定位   代码   

XXVIII.[TopCoder12693]EnclosingTriangle

经典套路是固定一个点,求出所有合法的剩余两个点。

为了方便,我们将环状的图形拆开,拆成 \(4n\) 个点。然后,我们枚举一个点 \(i\) 明显发现,剩下两个点必定位于 \(i\) 两侧的一端区间内,不妨设一半是 \([L_i,i)\),另一半是 \((i,R_i]\)。此部分可以通过求出当前点与全部二十个点间的向量中倾角最大以及最小的两个,并且求出它们与正方形的交点并取整得到,复杂度 \(O(mn)\)

然后,考虑我们枚举第一个点 \(i\)。则第二个点必定在 \(\Big(i,\min(4m-1,R_i)\Big]\) 中,第三个点必在 \([L_i,4m-1]\) 中(因为要保证三个点递增)。于是,我们用two-pointers维护所有合法的第二个点 \(j\),并用线段树维护所有这样的 \(j\)\((j,R_j]\) 上的带权和。之后,询问第三个点可能在的位置的带权和即可。复杂度 \(O(m\log m)\)

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const double eps=1e-10;
int cmp(double x){
	if(x>eps)return 1;
	if(x<-eps)return -1;
	return 0;
}
class EnclosingTriangle{
private:
	int n,m,L[400100],R[400100],N;
	struct Vector{
		double x,y;
		Vector(){}
		Vector(double X,double Y){x=X,y=Y;}
		friend Vector operator +(const Vector &u,const Vector &v){return Vector(u.x+v.x,u.y+v.y);}
		friend Vector operator -(const Vector &u,const Vector &v){return Vector(u.x-v.x,u.y-v.y);}
		friend Vector operator *(const Vector &u,const double &v){return Vector(u.x*v,u.y*v);}
		friend Vector operator /(const Vector &u,const double &v){return Vector(u.x/v,u.y/v);}
		friend double operator &(const Vector &u,const Vector &v){return u.x*v.y-u.y*v.x;}//cross times
		friend double operator |(const Vector &u,const Vector &v){return u.x*v.x+u.y*v.y;}//point times
		double operator ~()const{return sqrt(x*x+y*y);}//the modulo of a vector
		double operator !()const{return atan2(y,x);}//the angle of a vector
		void print(){printf("(%lf,%lf)",x,y);}
	}p[30];
	typedef Vector Point;
	struct Line{
		Point x,y;
		Vector z;
		Line(){}
		Line(Point X,Point Y){x=X,y=Y,z=Y-X;}
		friend Point operator &(const Line &u,const Line &v){return u.x+u.z*((v.z&(u.x-v.x))/(u.z&v.z));}
	}bd[4];
	typedef Line Segment;
	int code(int x,int y){//code a point into an identification
		if(y==0)return x;
		if(x==m)return y+m;
		if(y==m)return 3*m-x;
		if(x==0)return 4*m-y;
	}
	int side(int x,int y){//find the side of a point
		int ret=0;
		if(y==0)ret|=1;
		if(x==m)ret|=2;
		if(y==m)ret|=4;
		if(x==0)ret|=8;
		return ret;
	}
	Point deco(int id){//deco an identification into a point
		(id+=N)%=N;
		if(id<m)return Point(id,0);
		if(id<2*m)return Point(m,id-m);
		if(id<3*m)return Point(3*m-id,m);
		if(id<4*m)return Point(0,4*m-id);
	}
	int Crossover(Line l,int tp,int rd){//rd=1:round to maximal; rd=-1:round to minimal
		if(!cmp(l.z&bd[tp].z))return -1;//two lines parallel
		Point i=l&bd[tp];
		if(cmp(i.x-m)==1||cmp(i.x)==-1||cmp(i.y-m)==1||cmp(i.y)==-1)return -1;//outside the boundary
		int u,v;
		if(tp==0){
			u=i.x,v=u+1;
			if(cmp(u-i.x)==0)return code(u,0);//coincide.
			if(cmp(v-i.x)==0)return code(v,0);
			return rd==1?code(v,0):code(u,0);
		}
		if(tp==1){
			u=i.y,v=u+1;
			if(cmp(u-i.y)==0)return code(m,u);
			if(cmp(v-i.y)==0)return code(m,v);
			return rd==1?code(m,v):code(m,u);
		}
		if(tp==2){
			v=i.x,u=v+1;
			if(cmp(u-i.x)==0)return code(u,m);
			if(cmp(v-i.x)==0)return code(v,m);
			return rd==1?code(v,m):code(u,m);
		}
		if(tp==3){
			v=i.y,u=v+1;
			if(cmp(u-i.y)==0)return code(0,u);
			if(cmp(v-i.y)==0)return code(0,v);
			return rd==1?code(0,v):code(0,u);
		}
	}
	int findlimit(Line l,int rd,int ban){
		for(int i=0;i<4;i++)if(!(ban&(1<<i))){
			int tmp=Crossover(l,i,rd);
//			printf("%d:%d\n",i,tmp);
			if(tmp!=-1)return tmp;
		}
	}
	#define lson x<<1
	#define rson x<<1|1
	#define mid ((l+r)>>1)
	struct SegTree{int tag;ll sum;}seg[1001000];
	void ADD(int x,int y,int l,int r){seg[x].sum+=1ll*(r-l+1)*y,seg[x].tag+=y;}
	void pushup(int x){seg[x].sum=seg[lson].sum+seg[rson].sum;}
	void pushdown(int x,int l,int r){ADD(lson,seg[x].tag,l,mid),ADD(rson,seg[x].tag,mid+1,r),seg[x].tag=0;}
	void modify(int x,int l,int r,int L,int R,int val){
		if(l>R||r<L)return;
		if(L<=l&&r<=R){ADD(x,val,l,r);return;}
		pushdown(x,l,r),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),pushup(x);
	}
	ll query(int x,int l,int r,int L,int R){
		if(l>R||r<L)return 0;
		if(L<=l&&r<=R)return seg[x].sum;
		pushdown(x,l,r);return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
	}
	void modify(int x,int val){modify(1,0,N-1,x+1,R[x]<x?N-1:R[x],val);}
public:
	ll getNumber(int M,vector<int>X,vector<int>Y){
		m=M,n=X.size(),N=4*M;
		bd[0]=Line(Vector(0,0),Vector(m,0));
		bd[1]=Line(Vector(m,0),Vector(m,m));
		bd[2]=Line(Vector(m,m),Vector(0,m));
		bd[3]=Line(Vector(0,m),Vector(0,0));
		for(int i=0;i<n;i++)p[i]=Vector(X[i],Y[i]);
		for(int i=0;i<4*m;i++){
			Point q=deco(i),mn=p[0],mx=p[0];
			for(int j=1;j<n;j++){
				if(cmp((p[j]-q)&(mn-q))==-1)mn=p[j];
				if(cmp((p[j]-q)&(mx-q))==1)mx=p[j];
			}
//			q.print(),mn.print(),mx.print(),puts("");
			L[i]=findlimit(Line(q,mn),1,side(q.x,q.y));
			R[i]=findlimit(Line(q,mx),-1,side(q.x,q.y));
//			printf("%d %d\n",L[i],R[i]);
		}
		ll res=0;
		for(int i=0,j=1;i<N;){
			if(L[i]<i)break;
			while(j!=(R[i]+1)%N)modify(j,1),(++j)%=N;
			res+=query(1,0,N-1,L[i],4*m-1);
//			printf("%d\n",res);
			modify(++i,-1);
		}
		return res;
	}
}my;

[TopCoder12693]EnclosingTriangle

标签:复杂度   puts   operator   its   break   vat   std   定位   代码   

原文地址:https://www.cnblogs.com/Troverld/p/14619453.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!