本文将同步发布于:

题目

题目链接:洛谷 P3122USACO 官网

题意概述

给你平面上的一些点和直线,有两种操作:

  • 新加入一个点 \((x,y)\);
  • 给定一条直线 \(ax+by=c\),询问是否所有点都在这条直线的同侧(在直线上不合法)。

初始时有 \(n\leq 10^5\) 个点,共有 \(q\leq 10^5\) 次操作。

题解

对题意转化

我们考虑将 所有点都在直线的同一侧 这一条件进行转化。

具体地,我们先考虑一个简单的子问题。

简单子问题

问题是这样的,对于一条标准形式的直线 \(ax+by+c=0\),在它同侧的点 \((x_p,y_p)\) 满足什么性质?

我们倒推并分类讨论:

  • 若 \(ax_p+by_p+c=0\),显然点 \((x_p,y_p)\) 在这条直线上;
  • 若 \(ax_p+by_p+c<0\),显然它与所有点 \(q\) 满足 \(ax_q+by_q+c<0\) 在直线的同侧;
  • 若 \(ax_p+by_p+c>0\),显然它与所有点 \(q\) 满足 \(ax_q+by_q+c>0\) 在直线的同侧;

因此我们发现,如果两个点在一条直线的同侧,则将两点坐标代入直线方程得到的结果同号。


解决了子问题,我们对题意进行转化,得到如下式子。

一条直线合法当且仅当

\[\forall p\in S,\operatorname{sgn}(ax_p+by_p-c)=\operatorname{sgn}(ax_q+by_q-c)
\]

意思就是所有点对应的符号相同(暂时不考虑点在直线上)。

进一步地,一堆数同号说明它们的最大值与最小值同号。

问题转变成为,给定一条直线 \(ax+by-c=0\),求

\[\max_{p\in S}\{ax_p+by_p-c\}
\]
\[\min_{p\in S}\{ax_p+by_p-c\}
\]

利用几何性质解决问题

先来求解最大值吧。

设直线为 \(ax+by-c=\texttt{max}\)。

先将直线转化为斜截式:

\[y=-\frac{a}{b}x+\frac{c+\texttt{sum}}{b}
\]

我们发现:

  • 若 \(b>0\),我们只需要最大化该直线在 \(y\) 轴上的截距即可,维护一个上凸包,在上凸包上二分斜率求解即可;
  • 若 \(b<0\),我们则可以通过变号等方法修改成为 \(b>0\) 的情况;
  • 若 \(b=0\),我们发现此时的最大值必定在凸包的右端点取到,若用 \(\texttt{max}\) 值作为判据,则不受影响,无需考虑。

再来求解最小值,还是一样的步骤:

设直线为 \(ax+by-c=\texttt{min}\)。

先将直线转化为斜截式:

\[y=-\frac{a}{b}x+\frac{c+\texttt{min}}{b}
\]

我们发现:

  • 若 \(b>0\),我们只需要最小化该直线在 \(y\) 轴上的截距即可,维护一个下凸包,在下凸包上二分斜率求解即可;
  • 若 \(b<0\),我们则可以通过变号等方法修改成为 \(b>0\) 的情况;
  • 若 \(b=0\),我们发现此时的最小值必定在凸包的右端点取到,若用 \(\texttt{min}\) 值作为判据,则不受影响,无需考虑。

分治方法优化转移

上述方法需要动态维护两个凸包,并且凸包的横坐标不具有单调性,这需要用 平衡树 来维护。

考虑到本题并不强制在线,我们考虑离线下来,利用 cdq 分治来维护凸包,时间复杂度为 \(\Theta(n\log^2n)\)(视作 \(n,q\) 同阶)。

具体地,我们考虑对点和直线的加入时间进行分治,假设当前要处理区间 \([l,r]\) 内的事件。我们就只要考虑 区间 \([l,\texttt{mid}]\) 内的点形成的凸包对 区间 \([\texttt{mid}+1,r]\) 内直线的贡献即可。

维护凸包所需时间复杂度为排序的 \(\Theta(n\log_2n)\),结合主定理分析可知最终时间复杂度为 \(\Theta(n\log_2^2n)\)。

参考程序

更多细节参见参考程序。

#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
static char buf[1<<21],*p1=buf,*p2=buf;
#define flush() (fwrite(wbuf,1,wp1,stdout),wp1=0)
#define putchar(c) (wp1==wp2&&(flush(),0),wbuf[wp1++]=c)
static char wbuf[1<<21];int wp1;const int wp2=1<<21;
inline int read(void){
reg bool f=false;
reg char ch=getchar();
reg int res=0;
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();
return f?-res:res;
} inline ll readll(void){
reg bool f=false;
reg char ch=getchar();
reg ll res=0;
while(!isdigit(ch))f|=(ch=='-'),ch=getchar();
while(isdigit(ch))res=10*res+(ch^'0'),ch=getchar();
return f?-res:res;
} inline void writeln(const char* s){
while(*s) putchar(*(s++));
putchar('\n');
return;
} inline ll max(reg ll a,reg ll b){
return a>b?a:b;
} inline ll min(reg ll a,reg ll b){
return a<b?a:b;
} struct Vector{
int x,y;
inline Vector(reg int x=0,reg int y=0):x(x),y(y){
return;
}
inline Vector operator+(const Vector& a)const{
return Vector(x+a.x,y+a.y);
}
inline Vector operator-(const Vector& a)const{
return Vector(x-a.x,y-a.y);
}
}; inline ll dot(const Vector& a,const Vector& b){
return 1ll*a.x*b.x+1ll*a.y*b.y;
} inline ll cross(const Vector& a,const Vector& b){
return 1ll*a.x*b.y-1ll*a.y*b.x;
} typedef Vector Point; inline bool operator<(const Point& a,const Point& b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
} const int MAXN=1e5+5;
const int MAXQ=1e5+5;
const ll inf=5e18; struct updates{
int tim;
Point p;
}; struct querys{
int tim;
int A,B;
ll C;
ll Max,Min;
}; int n,q;
int totu,totq;
updates up[MAXN+MAXQ];
querys qu[MAXQ]; inline ll getVal(const querys& q,const Point& p){
return 1ll*q.A*p.x+1ll*q.B*p.y-q.C;
} inline void solve(reg int l,reg int r,reg int lu,reg int ru,reg int lq,reg int rq){
if(l==r)
return;
if(lu>ru||lq>rq)
return;
reg int mid=(l+r)>>1;
reg int midu,midq;
if(up[lu].tim<=mid){
reg int __l=lu,__r=ru,__mid;
while(__l<__r){
__mid=(__l+__r)>>1;
if(up[__mid+1].tim<=mid)
__l=__mid+1;
else
__r=__mid;
}
midu=__l;
}
else
midu=lu-1;
if(qu[lq].tim<=mid){
reg int __l=lq,__r=rq,__mid;
while(__l<__r){
__mid=(__l+__r)>>1;
if(qu[__mid+1].tim<=mid)
__l=__mid+1;
else
__r=__mid;
}
midq=__l;
}
else
midq=lq-1;
solve(l,mid,lu,midu,lq,midq);
if(lu<=midu&&midq+1<=rq){
reg int tot=0;
static Point tmp[MAXN+MAXQ];
for(reg int i=lu;i<=midu;++i)
tmp[++tot]=up[i].p;
sort(tmp+1,tmp+tot+1);
reg int top;
static Point S[MAXN+MAXQ];
top=0;
for(reg int i=1;i<=tot;++i){
while(top>1&&cross(S[top]-S[top-1],tmp[i]-S[top-1])>=0)
--top;
S[++top]=tmp[i];
}
for(reg int i=midq+1;i<=rq;++i){
reg int __l=1,__r=top,__mid;
while(__l<__r){
__mid=(__l+__r)>>1;
if(getVal(qu[i],S[__mid])<getVal(qu[i],S[__mid+1]))
__l=__mid+1;
else
__r=__mid;
}
qu[i].Max=max(qu[i].Max,getVal(qu[i],S[__l]));
}
top=0;
for(reg int i=1;i<=tot;++i){
while(top>1&&cross(S[top]-S[top-1],tmp[i]-S[top-1])<=0)
--top;
S[++top]=tmp[i];
}
for(reg int i=midq+1;i<=rq;++i){
reg int __l=1,__r=top,__mid;
while(__l<__r){
__mid=(__l+__r)>>1;
if(getVal(qu[i],S[__mid])>getVal(qu[i],S[__mid+1]))
__l=__mid+1;
else
__r=__mid;
}
qu[i].Min=min(qu[i].Min,getVal(qu[i],S[__l]));
}
}
solve(mid+1,r,midu+1,ru,midq+1,rq);
return;
} int main(void){
n=read(),q=read();
for(reg int i=1;i<=n;++i){
++totu;
up[totu].tim=0,up[totu].p.x=read(),up[totu].p.y=read();
}
for(reg int i=1;i<=q;++i){
static int opt;
opt=read();
switch(opt){
case 1:{
++totu;
up[totu].tim=i,up[totu].p.x=read(),up[totu].p.y=read();
break;
}
case 2:{
++totq;
qu[totq].tim=i,qu[totq].A=read(),qu[totq].B=read(),qu[totq].C=readll(),qu[totq].Max=-inf,qu[totq].Min=inf;
if(qu[totq].B<0)
qu[totq].A=-qu[totq].A,qu[totq].B=-qu[totq].B,qu[totq].C=-qu[totq].C;
else if((!qu[totq].B)&&qu[totq].A<0)
qu[totq].A=-qu[totq].A,qu[totq].C=-qu[totq].C;
break;
}
}
}
solve(0,q,1,totu,1,totq);
for(reg int i=1;i<=totq;++i)
writeln((!qu[i].Max||!qu[i].Min||((qu[i].Max^qu[i].Min)>>63))?"NO":"YES");
flush();
return 0;
}

「题解」USACO15FEB Fencing the Herd G的更多相关文章

  1. 「题解」「美团 CodeM 资格赛」跳格子

    目录 「题解」「美团 CodeM 资格赛」跳格子 题目描述 考场思路 思路分析及正解代码 「题解」「美团 CodeM 资格赛」跳格子 今天真的考自闭了... \(T1\) 花了 \(2h\) 都没有搞 ...

  2. 「题解」「HNOI2013」切糕

    文章目录 「题解」「HNOI2013」切糕 题目描述 思路分析及代码 题目分析 题解及代码 「题解」「HNOI2013」切糕 题目描述 点这里 思路分析及代码 题目分析 这道题的题目可以说得上是史上最 ...

  3. 「题解」JOIOI 王国

    「题解」JOIOI 王国 题目描述 考场思考 正解 题目描述 点这里 考场思考 因为时间不太够了,直接一上来就着手暴力.但是本人太菜,居然暴力爆 000 ,然后当场自闭- 一气之下,发现对 60pts ...

  4. 「题解」:[loj2763][JOI2013]现代豪宅

    问题 A: 现代豪宅 时间限制: 1 Sec  内存限制: 256 MB 题面 题目描述 (题目译自 $JOI 2013 Final T3$「現代的な屋敷」) 你在某个很大的豪宅里迷路了.这个豪宅由东 ...

  5. 「题解」:$Simple$

    问题 A: $Simple$ 时间限制: 1 Sec  内存限制: 256 MB 题面 题面谢绝公开. 题解 不算数学的数学题?? 直接枚举会重.$60%$两种算法:1.无脑$vis$数组记录.2.$ ...

  6. 「题解」CF1468M Similar Sets

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:洛谷.CF1468M. 题意简述 给定 \(n\) 个集合 \(S_{1\sim n}\),问是否存在 \(i,j\) 满 ...

  7. 「题解」300iq Contest 2 H. Honorable Mention

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:gym102331H. 题意概述 给定一个长度为 \(n\) 的序列 \(a\),有 \(q\) 次询问,每次询问给定三个 ...

  8. 「题解」NWRRC2017 Grand Test

    本文将同步发布于: 洛谷博客: csdn: 博客园: 简书. 题目 题目链接:洛谷 P7025.gym101612G. 题意概述 给你一张有 \(n\) 个点 \(m\) 条边的无向图,无重边无自环, ...

  9. 「题解」:$Six$

    问题 A: Six 时间限制: 1 Sec  内存限制: 512 MB 题面 题面谢绝公开. 题解 来写一篇正经的题解. 每一个数对于答案的贡献与数本身无关,只与它包含了哪几个质因数有关. 所以考虑二 ...

随机推荐

  1. XCTF-web_python_template_injection

    web_python_template_injection 这里涉及到flask的ssti漏洞(服务端模板注入). 简单点说就是,在使用flask/jinja2的模板渲染函数render_templa ...

  2. (邹博ML)数学分析与概率论

    机器学习入门 深度学习和机器学习? 深度学习在某种意义上可以认为是机器学习的一个分支,只是这个分支非常全面且重要,以至于可以单独作为一门学科来进行研究. 回忆知识 求解S. 对数函数的上升速度 我们使 ...

  3. 在AWS Glue中使用Apache Hudi

    1. Glue与Hudi简介 AWS Glue AWS Glue是Amazon Web Services(AWS)云平台推出的一款无服务器(Serverless)的大数据分析服务.对于不了解该产品的读 ...

  4. 三、多线程之Thread与Runnable的区别

    Thread与Runnable的区别(用三个窗口同时出售10张车票为例子) 运行代码 运行结果 分析 System.out.println("开始测试多线程");class MyT ...

  5. 教你用SQL实现统计排名

    前言: 在某些应用场景中,我们经常会遇到一些排名的问题,比如按成绩或年龄排名.排名也有多种排名方式,如直接排名.分组排名,排名有间隔或排名无间隔等等,这篇文章将总结几种MySQL中常见的排名问题. 创 ...

  6. 纯vue3实现的svg可视化web组态编辑器。主要用于物联网mqtt实时系统图

    vue就是边做这个项目边学的 代码可能有点乱 还望各位大神勿喷 如果代码对您有帮助 麻烦辛苦帮我点个star 预览地址 https://svg.yaolunmao.top 如何使用 # 克隆项目 gi ...

  7. gitbook安装使用教程

    以下是gitbook的简略安装使用过程,可以参考一下.后续有时间我再回头修改完善实验目的:安装gitbook后,将相关的文件发布到gitlab上安装node.js在cmd下执行安装npm instal ...

  8. 008.Ansible文件管理模块

    一  stat模块 检查文件状态使用,模块获取文件的状态等信息,类似与linux中的STAT命令可以用来获取文件的属主.可读/写.文件状态等信息 [root@node1 ansible]#  stat ...

  9. 005.Python条件if语句

    一  流程控制 流程控制的定义 流程:代码执行的过程 流程控制:对代码执行过程的管控 流程控制三大结构: 顺序结构:从上到下,代码依次执行 分支结构: 一共4个 循环结构:while for 分支结构 ...

  10. Linux ll查看文件属性详解-软硬链接详解

    Linux文件属性及类型 [root@localhost ~]# ll anaconda-ks.cfg 文件类型 权限 硬连接数 文件的大小 文件的创建,修改时间 - rw-------. 1 roo ...