给出平面上n个点,其中1号点是可以移动的,但是移动的范围不能改变任意三个点所成的角的状态( [ 0 , π ) , [ π , π ] , ( π , 2 π ] [0,\pi),[\pi,\pi],(\pi,2\pi] [0,π),[π,π],(π,2π])。
求可移动的范围。
n ≤ 500000 n\leq 500000 n≤500000
画一个图可以感受出来,实际上1号点移动的范围就是不能越过其他点的任意一对点的连线。
这样有一个很直观的做法就是枚举两个点,加入它们连线向1号点方向的半平面,然后做个半平面交即可,时间复杂度是 O ( n 2 log n ) O(n^2\log n) O(n2logn)的
这显然不能接受。
我们将所有的点按照极角序排序,可以发现实际上真正有用的半平面是非常有限的。
观察到只有极角序相邻的点的连线,以及每个点关于1号点的对称点 的极角序相邻的两个点与这个点的连线是有用的
显然这些半平面的个数是 O ( n ) O(n) O(n)的,做个半平面交就好了。
时间复杂度 O ( n log n ) O(n\log n) O(nlogn)
#include <bits/stdc++.h>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 600005
using namespace std;
map<int,bool> h[N];
namespace geometry
{
const double eps=1e-10;
const double pi=acos(-1);
struct node
{
double x,y;
node(double _x=0,double _y=0){
x=_x,y=_y;}
};
node operator +(node x,node y) {
return node(x.x+y.x,x.y+y.y);}
node operator -(node x,node y) {
return node(x.x-y.x,x.y-y.y);}
node operator *(double x,node y) {
return node(x*y.x,x*y.y);}
double crs(node x,node y) {
return x.x*y.y-x.y*y.x;}
double ang(node x)
{
double v=atan2(x.y,x.x);
if(v<0) v+=2*pi;
return v;
}
struct line
{
node p,v;
line(){
};
line(node _p,node _v) {
p=_p,v=_v;}
};
node dot(line x,line y) {
return y.p+(crs(x.v,x.p-y.p)/crs(x.v,y.v))*y.v;}
bool inside(line x,node y)
{
return (crs(x.v,y-x.p)>eps);
}
bool in(line x,node y)
{
return abs(crs(x.v,y-x.p)<=eps);
}
}
using namespace geometry;
int t,n,n1,n2;
node a[N],ab[N];
line d[4*N],db[4*N];
struct px
{
double v;
int p;
friend bool operator <(px x,px y) {
return x.v<y.v;}
}u2[N];
int pre(int x) {
return (x==2)?n:x-1;}
int suf(int x) {
return (x==n)?2:x+1;}
bool cmp2(px x,px y)
{
return(x.v+eps<y.v||(abs(x.v-y.v)<=eps&&inside(d[y.p],d[x.p].p)));
}
double get()
{
fo(i,1,n1)
{
if(in(d[i],node(0,0))) return 0;
u2[i]=(px){
ang(d[i].v),i};
db[i]=d[i];
}
static int dq[4*N],d2[4*N];
n2=0;
sort(u2+1,u2+n1+1,cmp2);
fo(i,1,n1) d[i]=db[u2[i].p];
fo(i,1,n1) if(i==1||fabs(ang(d[i].v)-ang(d[i-1].v))>eps) d2[++n2]=i;
int l=1,r=2;dq[1]=d2[1],dq[2]=d2[2];
fo(i1,3,n2)
{
int i=d2[i1];
while(l<r&&!inside(d[i],dot(d[dq[r]],d[dq[r-1]]))) r--;
while(l<r&&!inside(d[i],dot(d[dq[l]],d[dq[l+1]]))) l++;
dq[++r]=i;
}
while(l+2<r&&!inside(d[dq[l]],dot(d[dq[r]],d[dq[r-1]]))) r--;
double s=0;
fo(i,l,r-2) s+=crs(dot(d[dq[i]],d[dq[i+1]]),dot(d[dq[i+1]],d[dq[i+2]]));
s+=crs(dot(d[dq[r-1]],d[dq[r]]),dot(d[dq[r]],d[dq[l]]));
s+=crs(dot(d[dq[r]],d[dq[l]]),dot(d[dq[l]],d[dq[l+1]]));
return s/2;
}
int main()
{
freopen("everdream.in","r",stdin);
freopen("everdream.out","w",stdout);
int tp;
cin>>tp;
cin>>t;
int cnt=0;
while(t--)
{
scanf("%d",&n);
n1=0;
fo(i,1,n) h[i].clear();
fo(i,1,n)
{
int x,y;
scanf("%d%d",&x,&y);
a[i]=(i==1)?node(x,y):node(x,y)-a[1];
ab[i]=a[i];
u2[i]=(px){
ang(a[i]),i};
}
//a[++n]=node(1e6,-1e6),a[++n]=node(1e6,1e6),a[++n]=node(-1e6,1e6),a[++n]=node(-1e6,-1e6);
sort(u2+2,u2+n+1);
fo(i,2,n) a[i]=ab[u2[i].p];
for(int i=2,j=3;i<=n;i++)
{
node w=(-1)*a[i];
while(crs(a[j],w)>0) j=suf(j);
if(pre(j)!=i&&!h[i][pre(j)])
{
h[i][pre(j)]=h[pre(j)][i]=1;
line w=line(a[i],a[pre(j)]-a[i]);
d[++n1]=(inside(w,node(0,0)))?w:line(a[pre(j)],a[i]-a[pre(j)]);
}
if(j!=i&&!h[i][j])
{
h[i][j]=h[j][i]=1;
line w=line(a[j],a[i]-a[j]);
d[++n1]=(inside(w,node(0,0)))?w:line(a[i],a[j]-a[i]);
}
if(j==i+1) j=suf(j);
if(!h[i][suf(i)])
{
h[i][suf(i)]=h[suf(i)][i]=1;
line w1=line(a[i],a[suf(i)]-a[i]);
d[++n1]=(inside(w1,node(0,0)))?w1:line(a[suf(i)],a[i]-a[suf(i)]);
}
}
d[++n1]=line(node(1e6,-1e6)-a[1],node(0,1e6));//右边界
d[++n1]=line(node(1e6,1e6)-a[1],node(-1e6,0));//上边界
d[++n1]=line(node(-1e6,1e6)-a[1],node(0,-1e6));//左边界
d[++n1]=line(node(-1e6,-1e6)-a[1],node(1e6,0));//下边界
printf("%.10lf\n",get());
}
}
文章浏览阅读167次。中国传统菜谱的英文翻译锦集第1部分、素菜类Vegetarian1.豪油冬菇Oyster Sauce Mushroom2.什笙上素Bamboo Vegetable3.红烧豆腐Fried Tofu4.炒素丁Vegetable Roll5.罗汉腐皮卷Vegetable Egg Roll6.素咕噜肉Vegetarian Sweet and Sour7.蒸山水豆腐Steam Tofu8.鲜菇扒菜胆Mushr..._基于php的家常菜谱教程网站的设计与实现 英文翻译
文章浏览阅读418次。Unlink!Unlink!Unlink!level6_x86作为一道堆溢出入门题,还是值得用来练练手,学习一下堆的基础的知识的。参考文献:ctf-wiki:https://ctf-wiki.github.io/ctf-wiki/pwn/linux/glibc-heap/unlink-zh/大佬博客:https://blog.csdn.net/weixin_41617275/article..._javious level6x86
文章浏览阅读4.5k次。这两门课,一个是大数据,一个是人工智能 都是现在炙手可热的学科。相对而言,大数据适用性更广一些。人工智能专业,毕业后不是大批用人单位都会有AI研发需求的。智能科学与技术专业和数据科学与大数据技术专业。智能科学与技术专业:科技永远是第一生产力社会在不断进步,科技也在不断发展现在更新换代的速度实在是太快了,但是科学技术是永远不会过时的。智能科学与技术专业,是面向高新技术产业的基础性本科专业知识覆盖面比较广。这个专业会涉及到机器人技术,新一代网络计算为基础的智能系统微机电系统等,对国民经济,工业生产以及日常生活都_数据科学与大数据技术和计算机科学与技术
文章浏览阅读3.4k次,点赞2次,收藏10次。https://blog.csdn.net/weixin_41622043/article/details/107623694_3dhdrp 3durp
文章浏览阅读2.1k次。y复制文本,d删除文本,p粘贴文本。移动命令(如:gg、G)h,j,k,l或方向键。d或y等命令删除或复制。_vim 选中
文章浏览阅读190次。今天项目开发,需要通过两个条件去查询数据库数据,同时只要满足一个条件就可以取出这个对象。所以通过取出的数据肯定会有重复,所以要去掉重复项。如果用list集合接收两次的返回对象,那么肯定是有重复对象在list集合中,一开始我想到的是TreeSet,但知道TreeSet存放对象,一定要重写compareto方法,进行排序规则。而我仅仅是去重,并不需要排序。 所以我就用了HashSet,下面也就..._比较 hashset、linkedhashset 和 treeset 三者的异同
文章浏览阅读1k次。在编辑器或者发行版游戏中,如果我们想切换一个场景,需要设置触发器或者手动设置按钮来调用SceneManagement中的函数。而这个脚本挂载到场景时按下按键就可以在屏幕上方或者下方展示所有Build Setting中的场景,按下按键就可以加载对应场景。将脚本挂载到任意物体上,也可以制作成预制体。在编辑器中运行游戏,按下键盘上~键(即上方数字1左边的按键)就可以调出所有场景,再按一下关闭,点击场景按钮切换到指定场景。Button Width:调整按钮宽度,若开启自适应按钮宽度,该项不造成影响,默认100。_unity切换display
文章浏览阅读50次。以前不知道使用代码管理工具,最后写的一些东西都没有了,由于硬盘坏了或者不小心格式化了之类的,后来使用了Git和Github来托管自己的代码和读书笔记方便了不少,到哪里只要有网就可以把自己的东西拷贝下来继续使用。我这里简单的记录一下我使用的过程,最简单的使用都是,高级的功能我一直没有使用到,虽然买一本《Git权威指南》但是很多东西用不到就不能够真的会。下面开始简单介绍我使用的方法,我这个...
文章浏览阅读9.6k次,点赞4次,收藏13次。jjjsjs_tf.losses.mean_squared_error
文章浏览阅读21次。1. 背景介绍拓扑学是数学中的一个分支,研究的是空间的性质和变形。而代数几何则是将代数方法应用于几何学中,研究的是代数对象和几何对象之间的关系。这两个领域看似毫不相关,但实际上它们之间有着紧密的联系。在代数几何中,我们经常需要研究代数对象的性质,比如说代数曲线、代数簇等等。而这些代数对象通常都可以看作是某个拓扑空间的子集。因此,拓扑
文章浏览阅读5.7k次,点赞8次,收藏75次。Linux系统—read、write函数ssize_t read(int fd, void *buf, size_t count);//将文件中的数据读入内存ssize_t write(int fd, const void *buf, size_t count);//把内存中的数据写入到文件里实现文件拷贝:1.1 read函数输入以下命令查看函数帮助文档:man 2 read/write#include <unistd.h>ssize_t read(int fd, v_read函数实现
文章浏览阅读551次。本文实例为大家分享了微信小程序实现自动定位的具体代码,供大家参考,具体内容如下使用了腾讯地图提供的免费api:需要引入一个js文件:下载地址js代码:// 引入SDK核心类var QQMapWX = require('../../libs/qqmap-wx-jssdk.js');var qqmap = new QQMapWX({//在腾讯地图开放平台申请密钥 http://lbs.qq.com/m..._安卓小程序实时定位功能