zoukankan      html  css  js  c++  java
  • 【XSY3812】鱼死网破(计算几何?)

    题面

    在这里插入图片描述
    在这里插入图片描述

    题解

    先对于每个 x x x 轴上方的点,找到所有墙,按照极角排序,合并重合的墙。

    对于每一个端点引一条射线,左端点的射线权值是 + 1 +1 +1,右端点是 − 1 -1 1,可以发现一个点不能看到的点数等于这个点左边的射线的权值和。

    观察到这些直线都经过至少一个墙的端点,可以将这些直线按照经过的端点分类,每一类内极角排序。然后查询的时候对于每一堵墙二分查询就好了。

    时间复杂度 O ( k ( n + m ) log ⁡ n ) O(k(n+m)log n) O(k(n+m)logn)

    代码如下:

    #include<bits/stdc++.h>
    
    #define K 55
    #define N 100010
    #define eps 1e-11
    
    using namespace std;
    
    int compare(double a,double b)
    {
    	if(fabs(a-b)<eps) return 0;
    	return a<b?(-1):1;
    }
    
    struct Point
    {
    	int x,y;
    	Point(){};
    	Point(int a,int b){x=a,y=b;}
    	double get(){return atan2(y,x);}
    }a[N],wall[K][2];
    
    Point operator - (Point a,Point b)
    {
    	return Point(a.x-b.x,a.y-b.y);
    }
    
    struct Line
    {
    	double deg;
    	int val,id;
    	Line(){};
    	Line(double a,int b,int c){deg=a,val=b,id=c;}
    }l[N][K<<1];
    
    bool operator < (Line a,Line b)
    {
    	if(!compare(a.deg,b.deg)) return a.val>b.val;
    	return compare(a.deg,b.deg)==-1;
    }
    
    int n,m,k,opt;
    
    vector<double>deg[K][2];
    
    bool cmp(double a,double b)
    {
    	return compare(a,b)==-1;
    }
    
    int upper(int i,double x)
    {
    	int l=0,r=deg[i][0].size()-1,ans=-1;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(compare(deg[i][0][mid],x)!=1) ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ans+1;
    }
    
    int lower(int i,double x)
    {
    	int l=0,r=deg[i][1].size()-1,ans=-1;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(compare(deg[i][1][mid],x)==-1) ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	return ans+1;
    }
    
    int main()
    {
    	scanf("%d%d%d%d",&n,&k,&m,&opt);
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&a[i].x,&a[i].y);
    	for(int i=1;i<=k;i++)
    	{
    		scanf("%d%d%d",&wall[i][0].x,&wall[i][1].x,&wall[i][0].y);
    		wall[i][1].y=wall[i][0].y;
    		if(wall[i][0].x>wall[i][1].x) swap(wall[i][0].x,wall[i][1].x);
    	}
    	for(int i=1;i<=n;i++)
    	{
    		for(int j=1;j<=k;j++)
    		{
    			l[i][(j<<1)-1]=Line((wall[j][0]-a[i]).get(),1,j);
    			l[i][j<<1]=Line((wall[j][1]-a[i]).get(),-1,j);
    		}
    		sort(l[i]+1,l[i]+(k<<1)+1);
    		int tmp=0;
    		for(int j=1;j<=(k<<1);j++)
    		{
    			if(l[i][j].val==1)
    			{
    				if(!tmp) deg[l[i][j].id][0].push_back(l[i][j].deg);
    				tmp++;
    			}
    			else
    			{
    				tmp--;
    				if(!tmp) deg[l[i][j].id][1].push_back(l[i][j].deg);
    			}
    		}
    	}
    	for(int i=1;i<=k;i++)
    		for(int j=0;j<2;j++)
    			sort(deg[i][j].begin(),deg[i][j].end(),cmp);
    	int ans=0;
    	for(int i=1;i<=m;i++)
    	{
    		Point b;
    		scanf("%d%d",&b.x,&b.y);
    		if(opt) b.x^=ans,b.y^=ans;
    		ans=n;
    		for(int j=1;j<=k;j++)
    		{
    			ans-=upper(j,(b-wall[j][0]).get());
    			ans+=lower(j,(b-wall[j][1]).get());
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    /*
    2 1 1 0
    0 8
    1 7
    2 114514 6
    8 -1
    */
    

    我傻了,不应该用 double直接算极角的,因为这样精度要开到很小才能过,其实直接用叉乘来判断两条线的极角顺序就好了。

  • 相关阅读:
    禅道技术官网
    mysql中获取一天、一周、一月时间数据的各种sql语句写法
    使用HttpFileServer自建下载服务器
    axure新手入门教程
    Mysql存储过程查询结果赋值到变量的方法
    mysql 数据表中查找、删除重复记录
    oracle中的sql%rowcount,sql%found、sql%notfound、sql%rowcount和sql%isopen
    存储过程中的when others then 和 raise
    Oracle的DBMS_OUTPUT.PUT_LINE用法及脚本批处理方法
    oracle 特殊符号
  • 原文地址:https://www.cnblogs.com/ez-lcw/p/14448632.html
Copyright © 2011-2022 走看看