zoukankan      html  css  js  c++  java
  • [TopCoder12693]EnclosingTriangle

    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;
    

  • 相关阅读:
    在物理机上安装Ubuntu指南
    C语言程序设计-现代方法(笔记3)
    C语言程序设计-现代方法(笔记2)
    C语言程序设计-现代方法(笔记1)
    颠覆完美软件:软件测试必须知道的几件事(总结)
    颠覆完美软件:软件测试必须知道的几件事(读书笔记6)
    颠覆完美软件:软件测试必须知道的几件事(读书笔记5)
    颠覆完美软件:软件测试必须知道的几件事(读书笔记4)
    pycharm 引入虚环境
    性能测试之tsung
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619453.html
Copyright © 2011-2022 走看看