题意:
维护一个点集,支持两种操作:
(1) 插入点P(x,y).
(2)询问所有点是否在 直线Ax+By=C的同一侧。
分析:
显然可以用平衡树维护凸包,每次二分查找切线。但是代码比较复杂。
考虑cdq分治,按照输入的顺序,左区间的点对右区间的询问都会有影响。所以直接求出左区间点构成的凸包,静态查询右边区间的直线是否切割凸包即可。
对于直线Ax+By+C=0,令f(x)=Ax+By+C. f(x)的正负对应了点和直线的位置关系。并且|f(x)|正比于点到直线的距离。所以凸包上的点的f(x)值一定是单峰函数,所以可以用三分法求出极值,再判断正负即可。
三分好容易写挂,注意特判一下端点。
由此可见,CDQ分治在这个问题上和 平衡树维护凸包其实是完全等价的。
代码如下:
#include
#include
#include
#include
#include
#define LL long long
using namespace std;
const int maxn=300000+5;
const LL inf= 999999999999999LL;
template <class T>
inline void _read(T &x){
char ch=getchar(); bool mark=false;
for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
if(mark)x=-x;
}
int n,qq,N;
//Definition of Point and Vector
struct Point {
LL x,y;
Point(){}
Point (LL x,LL y):x(x),y(y){};
bool operator < (const Point p)const {
return xvoid put(){
cout<<"("<","<")";
}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){return Vector(A.x+B.x,A.y+B.y);}
Vector operator - (Vector A,Vector B){return Vector(A.x-B.x,A.y-B.y);}
LL Dot(Vector A,Vector B){return A.x*B.x+A.y*B.y;}
LL Cross(Vector A,Vector B){return A.x*B.y-A.y*B.x;}
//求凸包 返回 下凸包CH[0~rear1-1],上凸包CH[rear1~raer2-1];
Point CH[maxn];
int rear1,rear;
void ConvexHull(Point P[],int n){
//cout<<"IN function ConvexHull: n= "<
//cout<<"Point[]:";for(int i=1;i<=n;i++)P[i].put();cout<
sort(P+1,P+1+n);
int i;
rear=0;
for(i=1;i<=n;i++){
while(rear>1&&Cross(CH[rear-1]-CH[rear-2],P[i]-CH[rear-2])<=0) rear--;
CH[rear++]= P[i];
}
rear1=rear;
for(i=n-1;i>0;i--){
while(rear>rear1 && Cross(CH[rear-1]-CH[rear-2],P[i]-CH[rear-2])<=0) rear--;
CH[rear++]= P[i];
}
if(n>1) rear--;
//cout<<"return with rear= "<struct operation{
LL x,y,z,Max;
int ans;
}op[maxn];
LL F(int l,Point p){
return op[l].x*p.x+op[l].y*p.y+op[l].z;
}
LL f(LL x){if(!x)return 0 ;return x>0? 1:-1;}
//三分求 Max & Min
Point Q[maxn];
LL GetMax(int L,int R,int l){
if(Rreturn -inf;
LL Max= max(F(l,CH[L]),F(l,CH[R]));
while(true){
if(R-L<=5){
for(int i=L;i<=R;i++) Max=max(Max,F(l,CH[i]));
return Max;
}
int lmid=L+(R-L+1)/3,rmid=R-(R-L+1)/3;
LL f1=F(l,CH[lmid]),f2=F(l,CH[rmid]);
if(f1>f2) R=rmid;
else L=lmid;
}
}
LL GetMin(int L,int R,int l){
if(Rreturn inf;
LL Min= min(F(l,CH[L]),F(l,CH[R]));
while(true){
if(R-L<=5){
for(int i=L;i<=R;i++) Min=min(Min,F(l,CH[i]));
return Min;
}
int lmid=L+(R-L+1)/3,rmid=R-(R-L+1)/3;
LL f1=F(l,CH[lmid]),f2=F(l,CH[rmid]);
if(f1else L=lmid;
}
}
//CDQ
void Solve(int L,int R){
if(L==R) return ;
int mid=(L+R)>>1;
Solve(L,mid);Solve(mid+1,R);
int i,j,m=0;
for(i=L;i<=mid;i++)
if(op[i].ans==-1) Q[++m]=Point(op[i].x,op[i].y);
if(!m) return ;
ConvexHull(Q,m);
for(i=mid+1;i<=R;i++)
if(op[i].ans==0){
LL Max=max( GetMax(0,rear1-1,i), GetMax(rear1,rear-1,i) );
LL Min=min( GetMin(0,rear1-1,i), GetMin(rear1,rear-1,i) );
if(Max==0||Min==0||f(Max)*f(Min)<0|| (f(Max)*f(op[i].Max)<0) )
op[i].ans=1;
op[i].Max= f(Max);
}
}
int main(){
int i,j,x,y,k;
_read(n); _read(qq);
for(i=1;i<=n;i++){
_read(op[i].x); _read(op[i].y);
op[i].ans=-1;
}
N=qq+n;
for(i=n+1;i<=N;i++){
_read(k);
if(k==1){
_read(op[i].x); _read(op[i].y);
op[i].ans=-1;
}
else {
_read(op[i].x); _read(op[i].y); _read(op[i].z);
op[i].z*=-1;
}
}
Solve(1,N);
for(i=1;i<=N;i++)
if(op[i].ans!=-1)
puts(op[i].ans==0? "YES":"NO");
return 0;
}
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const ll inf=1000000000000000LL;
template <typename T>
inline void _read(T& x){
char t=getchar();bool sign=true;
while(t<'0'||t>'9')
{if(t=='-')sign=false;t=getchar();}
for(x=0;t>='0'&&t<='9';t=getchar())x=x*10+t-'0';
if(!sign)x=-x;
}
int n,q;
struct point{
ll x,y;
point(){}
point(ll g,ll h){x=g;y=h;}
bool operator < (const point G) const {
if(x==G.x)return yelse return xoperator + (const point G) const {
return point(x+G.x,y+G.y);
}
point operator - (const point G) const {
return point(x-G.x,y-G.y);
}
};
ll dot(point a,point b){
return a.x*b.x+a.y*b.y;
}
ll cross(point a,point b){
return a.x*b.y-a.y*b.x;
}
double len(point a){
return sqrt(a.x*a.x+a.y*a.y);
}
struct node{
ll type,a,b,c,ans,last;
};
node work[500005];
ll f(point a,int t){
return a.x*work[t].a+a.y*work[t].b+work[t].c;
}
point p[500005];
int down,up;
void convex_closure(point s[],int k){
int i,j;
sort(s+1,s+1+k);
down=up=0;
for(i=1;i<=k;i++){
while(up>1&&cross(p[up-1]-p[up-2],s[i]-p[up-2])<=0)up--;
p[up++]=s[i];
}
down=up;
for(i=k-1;i;i--){
while(up>down&&cross(p[up-1]-p[up-2],s[i]-p[up-2])<=0)up--;
p[up++]=s[i];
}
if(k>1)up--;
}
ll getmax(int l,int r,int t){
if(rreturn -inf;
ll maxn=-inf;
maxn=max(f(p[l],t),f(p[r],t));
int i,j,k;
for(;;){
if(r-l<=6){
for(i=l;i<=r;i++){
maxn=max(maxn,f(p[i],t));
}
return maxn;
}
int lmid=l+(r-l+1)/3,rmid=lmid+(r-l+1)/3;
if(f(p[lmid],t)>f(p[rmid],t))r=rmid;
else l=lmid;
}
}
ll getmin(int l,int r,int t){
if(rreturn inf;
ll minn=inf;
minn=min(f(p[l],t),f(p[r],t));
int i,j,k;
for(;;){
if(r-l<=6){
for(i=l;i<=r;i++){
minn=min(minn,f(p[i],t));
}
return minn;
}
int lmid=l+(r-l+1)/3,rmid=lmid+(r-l+1)/3;
if(f(p[lmid],t)else l=lmid;
}
}
point temp[200005];
void cdq(int l,int r){
if(l==r)return;
int mid=(l+r)>>1;
//cout<<"cdq("<
cdq(l,mid);cdq(mid+1,r);
int i,j,k;
k=0;
for(i=l;i<=mid;i++){
if(work[i].type==1)temp[++k]=point(work[i].a,work[i].b);
}
if(k==0)return;
convex_closure(temp,k);
for(i=mid+1;i<=r;i++){
if(work[i].type==2){
ll maxn,minn;
maxn=max(getmax(0,down-1,i),getmax(down,up-1,i));
minn=min(getmin(0,down-1,i),getmin(down,up-1,i));
if(maxn>0)maxn=1;
if(maxn<0)maxn=-1;
if(minn>0)minn=1;
if(minn<0)minn=-1;
if(maxn==0||minn==0||(minn*maxn)<0||(maxn*work[i].last)<0)work[i].ans=-1;
work[i].last=maxn;
}
}
}
int main(){
int i,j,k;
cin>>n>>q;
for(i=1;i<=n;i++){
work[i].type=1;
_read(work[i].a);_read(work[i].b);
}
for(i=n+1;i<=n+q;i++){
_read(k);
if(k==1){
work[i].type=1;
_read(work[i].a);_read(work[i].b);
}
if(k==2){
work[i].type=2;
_read(work[i].a);_read(work[i].b);_read(work[i].c);
work[i].c=-work[i].c;
}
}
cdq(1,n+q);
for(i=n+1;i<=n+q;i++){
if(work[i].type==2){
if(work[i].ans==-1)puts("NO");
else puts("YES");
}
}
}