• CF1195F Geometers Anonymous Club


    XXIX.CF1195F Geometers Anonymous Club

    闵可夫斯基和是关于两个凸包的运算,其几何意义是所有来自两个凸包内部的向量之和所构成的集合。

    可以被证明的是,两个凸包的闵可夫斯基和,可以通过对两个凸包上的边按照极角大小排序后依次首尾相接得到。

    回到本题。依照我们上述理论,我们尝试求出闵可夫斯基和上的顶点数。因为两条边只要倾角不同就会形成一个顶点,所以问题转换为区间不同倾角数。

    于是问题就变成经典原题[SDOI2009]HH的项链,无论是莫队还是BIT均可。

    需要注意的是,在判断两个向量是否倾角不同时,有两种主流方法:atan2 法或是叉积法。但是,叉积法只能判是否共线,atan2 法实测会被卡精度。

    于是我们将两种方法结合,大范围用 atan2 判,小范围再用叉积判。当然也可以将所有的倾角全都化成最简分数的形式进行比较。

    实际使用时需要略微卡常,因为 atan2 和叉积本身都有着不小的常数。

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m;
    const double eps=1e-13;
    int cmp(double x){
    	if(x>eps)return 1;
    	if(x<-eps)return -1;
    	return 0;
    }
    struct Vector{
    	int x,y;
    	Vector(){}
    	Vector(int X,int 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 ll operator &(const Vector &u,const Vector &v){return 1ll*u.x*v.y-1ll*u.y*v.x;}//cross times
    	double operator!()const{return atan2(y,x);}
    	friend bool operator <(const Vector &u,const Vector &v){
    		int tmp=cmp(!u-!v);
    		if(tmp)return tmp==-1;
    		return (u&v)<0;
    	}
    	void print(){printf("(%d,%d)",x,y);}
    };
    typedef Vector Point;
    Vector read(){int x,y;scanf("%d%d",&x,&y);return Vector(x,y);}
    vector<Point>u[100100];
    vector<Vector>v[100100];
    vector<int>w[100100];
    vector<pair<int,int> >r[100100];
    map<Vector,int>mp;
    int res[100100],sum[100100];
    int t[100100];
    void ADD(int x){x++;while(x<=n)t[x]++,x+=x&-x;}
    int SUM(int x){int ret=0;while(x)ret+=t[x],x-=x&-x;return ret;}
    int main(){
    	scanf("%d",&n);
    	for(int i=1,m;i<=n;i++){
    		scanf("%d",&m),sum[i]=sum[i-1]+m;
    		for(int j=0;j<m;j++)u[i].push_back(read());
    		for(int j=0;j<m;j++)v[i].push_back(u[i][j]-u[i][(j+1)%m]);
    	}
    	for(int i=1;i<=n;i++)for(auto j:v[i])w[i].push_back(mp[j]),mp[j]=i;
    	scanf("%d",&m);
    	for(int i=1,x,y;i<=m;i++)scanf("%d%d",&x,&y),r[y].push_back(make_pair(x,i));
    	for(int i=1;i<=n;i++){
    		for(auto j:w[i])ADD(j);
    		for(auto j:r[i])res[j.second]=SUM(j.first)-sum[j.first-1];
    	}
    	for(int i=1;i<=m;i++)printf("%d\n",res[i]);
    	return 0;
    }
    

  • 相关阅读:
    入门学习
    SQL语句
    Jmeter录制badboy
    post方式提交数据
    get向服务器提交数据
    手机端解析json
    生成JSON字符串
    新闻客户端
    从网络下载的图片加缓存功能
    消息队列机制messageQuene
  • 原文地址:https://www.cnblogs.com/Troverld/p/14619458.html
Copyright © 2020-2023  润新知