• CQOI2017 小Q的草稿


    小Q的草稿

    小 Q 是个程序员。

    众所周知,程序员在写程序的时候经常需要草稿纸。小 Q 现在需要一张草稿纸用来画图,但是桌上只有一张草稿纸,而且是一张被用过很多次的草稿纸。

    草稿纸可以看作一个二维平面,小 Q 甚至已经给它建立了直角坐标系。以前每一次草稿使用过的区域,都可以近似的看作一个平面上的一个三角形,这个三角形区域的内部和边界都不能再使用。当然了,以前的草稿也没有出现区域重叠的情况。

    小 Q 已经在草稿纸上画上了一些关键点,这些关键点都在没使用过的区域。小 Q 想把这些关键点两两之间尽可能的用线段连接起来。连接两个关键点的线段有可能会穿过已经用过的草稿区域,这样显然不允许。于是小 Q 就想知道,有多少对关键点可以被线段连接起来,而且还不会穿过已经用过的区域。为了方便,小 Q 保证任意三个关键点不会共线。

    对于 (100\%) 的测试点,(1le V,Tle 1000,0 leq x_i,y_i leq 10^8),且都是整数。

    题解

    首先有显然的(O(n^2m))暴力:枚举两个点判断有没有三角形与线段相交。

    然后发现这个判断的过程可以加速。

    我们可以枚举其中一个点(i),然后对(j> i)的点和三角形极角排序+扫描线。

    显然对于某个角度范围,我们只需要判断离(i)点最近的那条线段是否遮挡了点(j)。这个可以用set维护,因为类似圆扫描线,这道题里三角形不相交,所以随着角度的变化,线段的相对顺序不会改变。

    注意扫描线的顺序:先加边,在问点,后删边。

    小优化:一个三角形只有一条边会有用,就是那条覆盖角度范围最大的那条边。

    时间复杂度(O(n^2log n))

    CO double pi=acos(-1);
    struct point {double x,y;};
    
    IN point operator+(CO point&a,CO point&b){
    	return (point){a.x+b.x,a.y+b.y};
    }
    IN point operator-(CO point&a,CO point&b){
    	return (point){a.x-b.x,a.y-b.y};
    }
    IN point operator*(CO point&a,double b){
    	return (point){a.x*b,a.y*b};
    }
    IN point operator/(CO point&a,double b){
    	return (point){a.x/b,a.y/b};
    }
    IN double cross(CO point&a,CO point&b){
    	return a.x*b.y-a.y*b.x;
    }
    IN double dot(CO point&a,CO point&b){
    	return a.x*b.x+a.y*b.y;
    }
    
    IN double angle(CO point&a){
    	return atan2(a.y,a.x);
    }
    IN double len(CO point&a){
    	return sqrt(a.x*a.x+a.y*a.y);
    }
    IN point intersect(CO point&a,CO point&u,CO point&b,CO point&v){
    	return b+v*cross(b-a,u)/cross(u,v);
    }
    
    CO int N=1e4+10;
    point p[N],q[N][3];
    
    struct event{
    	double w;
    	int o;
    	point a,b;
    }e[5*N];
    
    IN bool operator<(CO event&a,CO event&b){
    	return a.w!=b.w?a.w<b.w:a.o>b.o;
    }
    
    struct seg {point a,b;};
    double w;
    
    IN bool operator<(CO seg&a,CO seg&b){
    	return len(intersect((point){0,0},(point){cos(w),sin(w)},a.a,a.b-a.a))<
    		len(intersect((point){0,0},(point){cos(w),sin(w)},b.a,b.b-b.a));
    }
    
    set<seg> h;
    
    int main(){
    	int n=read<int>(),m=read<int>();
    	for(int i=1;i<=n;++i) read(p[i].x),read(p[i].y);
    	for(int i=1;i<=m;++i)for(int j=0;j<=2;++j) read(q[i][j].x),read(q[i][j].y);
    	int64 ans=0;
    	for(int i=1;i<=n;++i){
    		int tot=0;
    		for(int j=i+1;j<=n;++j)
    			e[++tot]=(event){angle(p[j]-p[i]),0,p[j]-p[i]};
    		for(int j=1;j<=m;++j){
    			pair<double,int> id(0,-1);
    			for(int k=0;k<=2;++k){
    				double l=angle(q[j][k]-p[i]),r=angle(q[j][(k+1)%3]-p[i]);
    				if(l>r) swap(l,r);
    				double w=r-l;
    				if(w>pi) w=2*pi-w;
    				id=max(id,make_pair(w,k));
    			}
    			int k=id.second;
    			double l=angle(q[j][k]-p[i]),r=angle(q[j][(k+1)%3]-p[i]);
    			if(l>r) swap(l,r);
    			double w=r-l;
    			if(w<pi){
    				e[++tot]=(event){l,1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    				e[++tot]=(event){r,-1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    			}
    			else{
    				e[++tot]=(event){-pi,1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    				e[++tot]=(event){l,-1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    				e[++tot]=(event){r,1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    				e[++tot]=(event){pi,-1,q[j][k]-p[i],q[j][(k+1)%3]-p[i]};
    			}
    		}
    		sort(e+1,e+tot+1);
    		for(int j=1;j<=tot;++j){
    			w=e[j].w;
    			if(e[j].o==1) h.insert((seg){e[j].a,e[j].b});
    			else if(e[j].o==-1) h.erase((seg){e[j].a,e[j].b});
    			else ans+=h.empty() or len(e[j].a)<
    				len(intersect((point){0,0},(point){cos(w),sin(w)},h.begin()->a,h.begin()->b-h.begin()->a));
    		}
    //		cerr<<i<<" ans="<<ans<<endl;
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    

    不知道为什么LOJ上用C++(NOI)就会挂?可能是编译器版本的问题。

  • 相关阅读:
    How to become a hacker
    逻辑地址、线性地址、物理地址和虚拟地址
    java configuration
    Java 理论与实践: 变还是不变?
    Teach Yourself Programming in Ten Years
    border padding margin , the difference among them
    hashCode方法,equals方法,HashSet,HasMap之间的关系
    工程名 显示红色叹号
    记The_C_Programming_Language的错误
    VIM简单介绍学习1
  • 原文地址:https://www.cnblogs.com/autoint/p/13189755.html
Copyright © 2020-2023  润新知