题解:P11370 [Ynoi2024] 堕天作战/虚空处刑

· · 题解

把多边形和询问挂在 x 轴建立的线段树结构上的 log 个节点上。这样对于询问 A 和边 B 的交点 p,其恰好被一个 A 询问拆出来的节点和边 B 拆出来的节点覆盖。这两个节点必成祖孙关系。

在祖先的节点 [x,y] 上考虑,即所有线段保留 [x,y] 部分。

如果 A 是 B 的祖先,那么所有边被视为直线,询问是一般线段。而多边形的边不在端点以外位置相交,因此这些“直线”是具有上下关系的,排序二分即可找到询问点是否被直线划开。这一部分,对边在区间分出的 log 个节点中插入,询问在分出的 log 个节点及其祖先(显然这也是 O(\log n) 的)上查询,这一部分复杂度是 O(n\log^2n) 的。

反之 B 是 A 的祖先,即查询视为直线,边为线段。首先全局询问有方法是建多边形凸包,和凸包有交说明有交否则无交。然而这要求全局线段联通,所以还需更细致的讨论。

在这里的方法是把线段连通成的图形分为三种:只和 x=l 有交和只和 x=r 有交或者都有(如果以多边形左右边界作为全局左右端点的话是必然至少经过边界的)。都有交的好处是又具有有序的结构。设连通块在左右边界上的范围为 [L_1,R_1],[L_2,R_2],先把询问在某个区间中的拿走,这样对每个又可以排序之后找到上下连通块,在连通块的凸包上询问即可。

考虑只和左边有交的:照样算出区间 [l,r],判掉和区间有交的,这样需要计算区间右端点 <L 的那些连通块所构成的凸包(大于、右侧的类似),这样的凸包一定有点 (x,l),(x,r) 且作为最左的两点。根据区间无交,这样的凸包可以在线性时间内合并为新凸包,因此做一遍扫描线即可判断,这里的总复杂度也是 O(n\log^2n)

代码实现是非常繁琐的,还有点卡常(不知道标算如何做到那么快)。

这是一份(大概会被卡成 ~ 80 分的)参考代码,如果你希望知道这份代码的实现细节可以私信等等。后面卡常就是尽量减少 O(n\log^2n) 部分(包括很多排序)的使用了。

#include<bits/stdc++.h>
using namespace std;
bool mst;
#define db double
// #define endl "\n"
const int maxn=2e5+5,N=3e4+5;
const db eps=1e-6,INF=1e18,eps2=1e-10;
struct pt{db x,y;};
pt operator +(pt A,pt B){return {A.x+B.x,A.y+B.y};}
pt operator -(pt A,pt B){return {A.x-B.x,A.y-B.y};}
db operator *(pt A,pt B){return A.x*B.x+A.y*B.y;}
db operator ^(pt A,pt B){return A.x*B.y-A.y*B.x;}
#define Poly vector<pt>
pt a[maxn];int n,q,VV=3e4+1;
pt qp[maxn],qq[maxn];int qres[maxn];
int mmn=VV+1,mmx=0;
struct line{pt p,q;};
inline int dcmp(db x){return (x>eps)-(x<-eps);}
inline int dcmp2(db x){return (x>eps2)-(x<-eps2);}
inline bool operator <(line A,line B){return dcmp(A.p.y-B.p.y)!=0?A.p.y<B.p.y:A.q.y<B.q.y;}
inline bool pd1(line L,pt A){return dcmp((A.x-L.p.x)*(L.q.y-L.p.y)-(A.y-L.p.y)*(L.q.x-L.p.x))<=0;}
inline bool pd2(line L,pt A){return dcmp((A.x-L.p.x)*(L.q.y-L.p.y)-(A.y-L.p.y)*(L.q.x-L.p.x))<0;}
inline line getL(line L,db l,db r){
    if(L.p.x==L.q.x)return L;
    pt p={l,1.0*(l-L.p.x)/(L.q.x-L.p.x)*(L.q.y-L.p.y)+L.p.y};
    pt q={r,1.0*(r-L.p.x)/(L.q.x-L.p.x)*(L.q.y-L.p.y)+L.p.y};
    return {dcmp(L.p.x-l)>=0?L.p:p,dcmp(r-L.q.x)>=0?L.q:q};
}
ostream & operator<<(ostream &o, const pt &p){o<<"["<<p.x<<" , "<<p.y<<"]";return o;}
ostream & operator<<(ostream &o, const line &L){o<<"{"<<L.p<<" , "<<L.q<<"}";return o;}
ostream & operator<<(ostream &o, const Poly &A){o<<"{";for(int i=0;i<A.size();i++){if(i!=A.size()-1)o<<A[i]<<" , ";else o<<A[i];}o<<"}";return o;}
ostream & operator<<(ostream &o, const vector<db> &A){o<<"{";for(int i=0;i<A.size();i++){if(i!=A.size()-1)o<<A[i]<<" , ";else o<<A[i];}o<<"}";return o;}
namespace PHS{
    line L[maxn];int tot=0;
    inline void ins(line A){L[++tot]=A;}void clear(){tot=0;}void predo(){sort(L+1,L+tot+1);}
    inline int pre1(pt p){
        int l=1,r=tot,res=0;
        while(l<=r){
            int mid=l+r>>1;
            if(pd1(L[mid],p))res=mid,l=mid+1;
            else r=mid-1;
        }
        return res; 
    }
    inline int pre2(pt p){
        int l=1,r=tot,res=0;
        while(l<=r){
            int mid=l+r>>1;
            if(pd2(L[mid],p))res=mid,l=mid+1;
            else r=mid-1;
        }
        return res; 
    }
    inline bool pd(pt p,pt q){
        int A=pre2(p);
        int B=A;while(B+1<=tot&&pd1(L[B+1],p))++B;if(B!=A)return 1;
        int C=pre2(q);if(C!=B)return 1;
        int D=C;while(D+1<=tot&&pd1(L[D+1],q))++D;if(D!=C)return 1;
        return 0;
    }
}
namespace SOLVE1{
    vector<int> I[N<<2],E[N<<2];
    namespace STS1{
        #define ls (k<<1)
        #define rs (k<<1|1)
        #define mid ((l+r)>>1)
        inline void ins(int k,int l,int r,int x,int y,int u){
            if(x>y)return ;
            if(x<=l&&r<=y){
                I[k].push_back(u);
                return ;
            }
            if(x<=mid)ins(ls,l,mid,x,y,u);
            if(mid<y)ins(rs,mid+1,r,x,y,u);
        }
        inline void ask(int k,int l,int r,int x,int y,int u){
            if(E[k].empty()||E[k].back()!=u)E[k].push_back(u);
            if((x<=l&&r<=y)||l==r)return ;
            if(x<=mid)ask(ls,l,mid,x,y,u);
            if(mid<y)ask(rs,mid+1,r,x,y,u);
        }
        inline void calc(int k,int l,int r){
            PHS::clear();
            for(auto i:I[k]){
                pt p=a[i],q=(i==n?a[1]:a[i+1]);
                if(p.x>q.x)swap(p,q);line L={p,q};
                PHS::ins(getL(L,l-1,r));
            }
            PHS::predo();
            for(auto u:E[k]){
                if(qres[u])continue;
                line G=getL((line){qp[u],qq[u]},l-1,r);
                qres[u]|=PHS::pd(G.p,G.q);
            }
            if(l==r)return ;
            calc(ls,l,mid),calc(rs,mid+1,r);
        }
    }
    inline void solve1(){
        for(int i=1;i<=n;i++){
            pt p=a[i],q=(i==n?a[1]:a[i+1]);
            if(p.x>q.x)swap(p,q);line L={p,q};
            STS1::ins(1,mmn+1,mmx,p.x+1,q.x,i);
        }
        for(int i=1;i<=q;i++){
            if(qp[i].x+1<=qq[i].x)STS1::ask(1,mmn+1,mmx,qp[i].x+1,qq[i].x,i);
            STS1::ask(1,mmn+1,mmx,qq[i].x+1,qq[i].x+1,i);
            STS1::ask(1,mmn+1,mmx,qp[i].x,qp[i].x,i);
        }
        STS1::calc(1,mmn+1,mmx);
    }   
}
inline db atan2(pt A){return atan2(A.y,A.x);}
inline db len(pt A){return A.x*A.x+A.y*A.y;}
inline db dis(pt A,pt B){return len(B-A);}  
pt DC;int stk[maxn],tp;db pra[maxn],prd[maxn];pt cp[maxn];int per[maxn];
inline bool cmpp(int x,int y){
    db sa=pra[x],sb=pra[y];
    if(dcmp2(sa-sb)==0)return prd[x]<prd[y];
    else return sa<sb;
}
inline db slope(pt x,pt y){
    if(dcmp(x.x-y.x)==0)return dcmp(y.y-x.y)<=0?-INF:INF;
    return (y.y-x.y)/(y.x-x.x);
}
namespace SOLVE2{
    Poly Convex(Poly p){int n=p.size();
        int C=0;for(int i=1;i<n;i++)if((dcmp(p[i].y-p[C].y)==0&&p[i].x<p[C].x)||dcmp(p[i].y-p[C].y)==-1)C=i;
        swap(p[C],p[0]);DC=p[0];for(int i=0;i<n;i++)cp[i]=p[i],per[i]=i;
        for(int i=1;i<n;i++)pra[i]=atan2(p[i]-DC),prd[i]=dis(p[i],DC);
        sort(per+1,per+n,cmpp);for(int i=1;i<n;i++)p[i]=cp[per[i]];
        stk[tp=1]=0;for(int i=1;i<n;i++){
            while(tp>1&&((p[i]-p[stk[tp-1]])^(p[stk[tp]]-p[stk[tp-1]]))>=0)--tp;
            stk[++tp]=i;
        }Poly N;for(int i=1;i<=tp;i++)N.push_back(p[stk[i]]);return N;
    }
    int vis[maxn<<1];
    db curL,curR;
    vector<int> te[maxn<<1];
    vector<Poly> PM;
    Poly PPM[maxn],PU[maxn],PD[maxn];
    vector<db> PUK[maxn],PDK[maxn];
    pair<pair<db,db>,int> PML[maxn],PMR[maxn];
    pair<db,int> lq[maxn],rq[maxn];int revL[maxn],revR[maxn];
    line cline[maxn];
    Poly CP[maxn];db CPL[maxn],CPR[maxn];int tot=0;
    Poly CPcur,CPN;vector<db> CKcur,CKN;
    inline Poly Standard(Poly A){
        db mx=-INF;int p;
        for(int i=0;i<A.size();i++){auto [x,y]=A[i];if(dcmp(x-curL)==0){if(dcmp(y-mx)>=0)mx=y,p=i;}}
        Poly B={A[p]};int y=p;p=(p==0?A.size()-1:p-1);while(p!=y)B.push_back(A[p]),p=(p==0?(int)A.size()-1:p-1);
        return B;
    }
    inline vector<db> calcCK(Poly A){
        vector<db> res;int c=A.size()-1;
        while(c>=1&&A[c].x<A[c-1].x)res.push_back(-slope(A[c-1],A[c])),--c;
        reverse(res.begin(),res.end());
        return res;
    }
    inline void merge(){
        int c=CPcur.size()-1;int ptl=CPN.size();
        for(int i=CPN.size()-1;i>=0;i--){
            while(c>0&&dcmp((CPN[i]-CPcur[c])^(CPcur[c-1]-CPcur[c]))>=0){
                if(CPcur[c].x<CPcur[c-1].x)CKcur.pop_back();--c;}
            ptl=i;if(i>0&&dcmp((CPN[i]-CPcur[c])^(CPN[i-1]-CPcur[c]))<=0)break;
        }
        while(CPcur.size()-1>c)CPcur.pop_back();
        vector<db> ccb;
        for(int i=ptl;i<CPN.size();i++){
            CPcur.push_back(CPN[i]);
            int S=CPcur.size();
            if(CPcur[S-1].x<CPcur[S-2].x)CKcur.push_back(-slope(CPcur[S-2],CPcur[S-1]));
        }
    }
    inline bool cpd(line A){
        if(CKcur.empty())return 0;
        db K=(A.q.y-A.p.y)/(A.q.x-A.p.x);
        int p=lower_bound(CKcur.begin(),CKcur.end(),-K)-CKcur.begin();
        p=CKcur.size()-p-1;db mn=INF;
        for(int j=(int)CPcur.size()-(p+3);j<(int)CPcur.size()-(p-3);j++)if(0<=j&&j<CPcur.size())mn=min(mn,CPcur[j].y-CPcur[j].x*K);
        mn+=curL*K;if(dcmp(A.p.y-mn)>=0)return 1;return 0;
    }
    vector<pt> V;vector<pair<int,int> > E; 
    int st[maxn];int ct=0;vector<int> sdv;
    vector<int> Spt[maxn];int cs=0;
    vector<int> cpt;
    struct PPHS{
        vector<pair<line,int> > CQ;
        int L,R;vector<int> H;
        inline void insL(int i){
            pair<pt,int> P={a[i],i},Q=(i==n?(pair<pt,int>){a[1],1}:(pair<pt,int>){a[i+1],i+1});
            if(P.first.x>Q.first.x)swap(P,Q);line cd={P.first,Q.first};
            line cda=getL(cd,L,R);int u,v;
            if(dcmp(P.first.x-L)>=0){if(!st[P.second])st[P.second]=++ct,sdv.push_back(P.second),V.push_back(a[P.second]);u=st[P.second]-1;}
            else V.push_back(cda.p),++ct,u=ct-1;
            if(dcmp(R-Q.first.x)>=0){if(!st[Q.second])st[Q.second]=++ct,sdv.push_back(Q.second),V.push_back(a[Q.second]);v=st[Q.second]-1;}
            else V.push_back(cda.q),++ct,v=ct-1;
            E.push_back({u,v});
        }
        inline void predo(){
            for(auto x:sdv)st[x]=0;sdv.clear();
            E.clear();ct=0;V.clear();
            for(auto x:H)insL(x);
        }
        inline void DFS(int u){
            if(vis[u])return ;
            cpt.push_back(u);vis[u]=1;
            for(auto v:te[u])DFS(v);
        }
        inline int Pre(int u,int i){i--;if(i==-1)i=PPM[u].size()-1;return i;}
        inline int Suf(int u,int i){i++;if(i==PPM[u].size())i=0;return i;}
        inline void solvecon(int u){
            int x=0;while(PPM[u][x].x>=PPM[u][Pre(u,x)].x)x=Pre(u,x);
            PU[u].clear(),PD[u].clear();PD[u].push_back(PPM[u][x]);
            int y=x;PDK[u].clear(),PUK[u].clear();
            while(PPM[u][x].x<=PPM[u][Suf(u,x)].x)x=Suf(u,x),PD[u].push_back(PPM[u][x]);
            PU[u].push_back(PPM[u][x]);x=Suf(u,x);while(x!=y)PU[u].push_back(PPM[u][x]),x=Suf(u,x);
            PU[u].push_back(PPM[u][y]);
            for(int i=0;i<PU[u].size()-1;i++)PUK[u].push_back(slope(PU[u][i+1],PU[u][i]));
            for(int i=0;i<PD[u].size()-1;i++)PDK[u].push_back(slope(PD[u][i],PD[u][i+1]));
        }
        inline db AskU(db K,int u){
            db mx=-INF;
            int p=lower_bound(PUK[u].begin(),PUK[u].end(),K)-PUK[u].begin();
            for(int i=p-3;i<=p+3;i++)if(0<=i&&i<PU[u].size())mx=max(mx,PU[u][i].y-PU[u][i].x*K);
            return mx;
        }
        inline db AskD(db K,int u){
            db mn=INF;
            int p=lower_bound(PDK[u].begin(),PDK[u].end(),K)-PDK[u].begin();
            for(int i=p-3;i<=p+3;i++)if(0<=i&&i<PD[u].size())mn=min(mn,PD[u][i].y-PD[u][i].x*K);
            return mn;
        }
        inline void calc(){curL=L,curR=R;
            PM.clear();
            for(int i=1;i<=cs;i++){
                cpt=Spt[i];int lc=0,rc=0;
                Poly ccpt;for(auto x:cpt)ccpt.push_back(V[x]);
                for(auto x:cpt)lc+=(dcmp(V[x].x-L)==0),rc+=(dcmp(V[x].x-R)==0);
                if(lc&&!rc)PM.push_back(ccpt);
            }
            int S=PM.size();
            if(!S)return ;
            for(int i=0;i<PM.size();i++){
                auto X=PM[i];db mn=INF,mx=-INF;
                for(auto [x,y]:X)if(dcmp(x-L)==0)mn=min(mn,y),mx=max(mx,y);
                PML[i]={{mn,mx},i};
            }
            sort(PML,PML+S);db cmn=-INF,cmx=-INF;
            vector<int> cur;for(int i=1;i<=tot;i++)CP[i].clear();tot=0;
            for(int i=0;i<S;i++){
                if(dcmp(PML[i].first.second-cmx)<=0)continue;
                if(dcmp(PML[i].first.first-cmx)>0){
                    if(cur.size()){++tot;for(auto x:cur){for(auto y:PM[x])CP[tot].push_back(y);}CPL[tot]=cmn,CPR[tot]=cmx;}
                    cur={PML[i].second};cmn=PML[i].first.first;cmx=PML[i].first.second;
                }else cur.push_back(PML[i].second),cmx=PML[i].first.second;
            }
            if(cur.size()){++tot;for(auto x:cur){for(auto y:PM[x])CP[tot].push_back(y);}CPL[tot]=cmn,CPR[tot]=cmx;}
            for(int i=1;i<=tot;i++)CP[i]=Standard(Convex(CP[i]));
            int cnt=0;
            for(auto [L,u]:CQ)if(!qres[u])lq[++cnt]={L.p.y,u};sort(lq+1,lq+cnt+1);CPcur.clear(),CKcur.clear();
            int cl=1;
            reverse(CPL+1,CPL+tot+1);reverse(CPR+1,CPR+tot+1);
            reverse(CP+1,CP+tot+1);reverse(lq+1,lq+cnt+1);CPR[tot+1]=-INF;
            for(int i=1;i<=tot+1;i++){
                while(cl<=cnt&&dcmp(lq[cl].first-CPR[i])>0){if(!qres[lq[cl].second])qres[lq[cl].second]|=cpd(cline[lq[cl].second]);++cl;}
                while(cl<=cnt&&dcmp(lq[cl].first-CPL[i])>=0&&dcmp(lq[cl].first-CPR[i])<=0)qres[lq[cl].second]=1,++cl;
                if(i<=tot){
                    if(i==1)CPcur=CP[i],CKcur=calcCK(CP[i]);
                    else CPN=CP[i],CKN=calcCK(CP[i]),merge();
                }
            }
        }
        inline void solve(){
            predo();vector<pair<line,int> > NCQ;
            for(auto [L,u]:CQ)if(!qres[u])NCQ.push_back({L,u});
            swap(CQ,NCQ);if(!CQ.size()||!E.size())return ;
            for(int i=0;i<V.size();i++)vis[i]=0,te[i].clear();
            for(auto [u,v]:E)te[u].push_back(v),te[v].push_back(u);
            PM.clear();cs=0;
            for(int i=0;i<V.size();i++){
                if(vis[i])continue;
                cpt.clear();DFS(i);int lc=0,rc=0;Spt[++cs]=cpt;
                Poly ccpt;for(auto x:cpt)ccpt.push_back(V[x]);
                for(auto x:cpt){
                    if(dcmp(V[x].x-L)==0)lc++;
                    if(dcmp(V[x].x-R)==0)rc++;
                }
                if(lc&&rc)PM.push_back(ccpt);
            }int S=PM.size();int cnt=0;
            for(auto x:PM)PPM[cnt++]=Convex(x);
            for(int i=0;i<S;i++){
                db mn=VV+1,mx=0;auto X=PM[i];
                for(auto x:X)if(dcmp(x.x-L)==0)mn=min(mn,x.y),mx=max(mx,x.y);
                PML[i]={{mn,mx},i};
            }
            for(int i=0;i<S;i++){
                db mn=VV+1,mx=0;auto X=PM[i];
                for(auto x:X)if(dcmp(x.x-R)==0)mn=min(mn,x.y),mx=max(mx,x.y);
                PMR[i]={{mn,mx},i};
            }int SQ=0;
            sort(PML,PML+S);sort(PMR,PMR+S);
            for(int i=0;i<S;i++)solvecon(i);
            for(auto [L,i]:CQ){
                auto [p,q]=L;
                lq[SQ]={p.y,i},rq[SQ]={q.y,i};
                ++SQ;
            }
            sort(lq,lq+SQ);sort(rq,rq+SQ);
            int cl=0,cr=0;
            for(int i=0;i<SQ;i++)revL[lq[i].second]=revR[rq[i].second]=S;
            for(int i=0;i<S;i++){
                auto [P,id]=PML[i];
                auto [l,r]=P;
                while(cl<SQ&&dcmp(lq[cl].first-l)<0)revL[lq[cl].second]=i,++cl;
                while(cl<SQ&&dcmp(lq[cl].first-l)>=0&&dcmp(r-lq[cl].first)>=0)qres[lq[cl].second]=1,++cl;
            }
            for(int i=0;i<S;i++){
                auto [P,id]=PMR[i];
                auto [l,r]=P;
                while(cr<SQ&&dcmp(rq[cr].first-l)<0)revR[rq[cr].second]=i,++cr;
                while(cr<SQ&&dcmp(rq[cr].first-l)>=0&&dcmp(r-rq[cr].first)>=0)qres[rq[cr].second]=1,++cr;
            }
            for(auto [Li,i]:CQ){
                if(qres[i])continue;
                if(revL[i]!=revR[i])qres[i]=1;
                else{
                    auto [p,q]=Li;
                    db K=slope(p,q);
                    pair<db,db> I1={-INF,INF},I2={-INF,INF};
                    if(revL[i]>0){
                        auto r=AskU(K,PML[revL[i]-1].second);
                        r+=L*K;
                        if(dcmp(r-p.y)>=0)qres[i]=1;
                    }
                    if(revL[i]<S){
                        auto l=AskD(K,PML[revL[i]].second);
                        l+=L*K;
                        if(dcmp(p.y-l)>=0)qres[i]=1;
                    }
                }
            }
            for(auto [L,u]:CQ)cline[u]=L;calc();
            for(auto &u:V)u.x=L+R-u.x;
            for(int i=0;i<CQ.size();i++)swap(CQ[i].first.p.y,CQ[i].first.q.y);
            for(auto [L,u]:CQ)cline[u]=L;calc();
            for(auto &u:V)u.x=L+R-u.x;
            for(int i=0;i<CQ.size();i++)swap(CQ[i].first.p.y,CQ[i].first.q.y);
            for(auto &u:V)u.y=VV-u.y;
            for(int i=0;i<CQ.size();i++)CQ[i].first.p.y=VV-CQ[i].first.p.y,CQ[i].first.q.y=VV-CQ[i].first.q.y;
            for(auto [L,u]:CQ)cline[u]=L;calc();
            for(auto &u:V)u.x=L+R-u.x;
            for(int i=0;i<CQ.size();i++)swap(CQ[i].first.p.y,CQ[i].first.q.y);
            for(auto [L,u]:CQ)cline[u]=L;calc();
        }
    }F[N<<2];
    namespace STS2{
        #define ls (k<<1)
        #define rs (k<<1|1)
        #define mid ((l+r)>>1)
        inline void ins(int k,int l,int r,int x,int y,int u){
            if(y<l||x>r)return ;
            if(F[k].H.empty()||F[k].H.back()!=u)F[k].H.push_back(u);
            if((x<=l&&r<=y)||(l==r))return ;
            if(x<=mid)ins(ls,l,mid,x,y,u);
            if(mid<y)ins(rs,mid+1,r,x,y,u);
        }
        inline void ask(int k,int l,int r,int x,int y,line L,int u){
            if(x<=l&&r<=y){F[k].CQ.push_back({getL(L,l-1,r),u});return ;}
            if(l==r)return ;
            if(x<=mid)ask(ls,l,mid,x,y,L,u);
            if(mid<y)ask(rs,mid+1,r,x,y,L,u);
        }
        inline void calc(int k,int l,int r){
            F[k].L=l-1,F[k].R=r,F[k].solve();
            if(l==r)return ;
            calc(ls,l,mid);calc(rs,mid+1,r);
        }
    }
    inline void solve2(){
        for(int i=1;i<=n;i++){
            pt P=a[i],Q=(i==n?a[1]:a[i+1]);
            if(P.x>Q.x)swap(P,Q);
            if(P.x<Q.x)STS2::ins(1,mmn+1,mmx,P.x+1,Q.x,i);
            else STS2::ins(1,mmn+1,mmx,P.x,P.x,i),STS2::ins(1,mmn+1,mmx,Q.x+1,Q.x+1,i);
        }
        for(int i=1;i<=q;i++){
            if(qres[i])continue;
            pt p=qp[i],q=qq[i];
            STS2::ask(1,mmn+1,mmx,p.x+1,q.x,(line){p,q},i);
        }
        STS2::calc(1,mmn+1,mmx);
    }
}
namespace SOLVE3{
    namespace ST{
        #define ls (k<<1)
        #define rs (k<<1|1)
        #define mid ((l+r)>>1)
        int xds[N<<2],add[N<<2];
        inline void ADD(int k,int v){xds[k]+=v,add[k]+=v;}
        inline void pushdown(int k){ADD(ls,add[k]),ADD(rs,add[k]),add[k]=0;}
        inline void pushup(int k){xds[k]=max(xds[ls],xds[rs]);}
        inline void modify(int k,int l,int r,int x,int y,int v){
            if(x<=l&&r<=y)return ADD(k,v);
            pushdown(k);if(x<=mid)modify(ls,l,mid,x,y,v);
            if(mid<y)modify(rs,mid+1,r,x,y,v);pushup(k);
        }
        inline int query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y)return xds[k];
            int res=0;pushdown(k);
            if(x<=mid)res=max(res,query(ls,l,mid,x,y));
            if(mid<y)res=max(res,query(rs,mid+1,r,x,y));
            return res;
        }
    }
    vector<array<int,3> > e[N];
    vector<array<int,3> > re[N];
    inline void solve3(){
        for(int i=1;i<=n;i++){
            pt P=a[i],Q=(i==n?a[1]:a[i+1]);
            if(dcmp(P.x-Q.x)==0){int L=(min(P.y,Q.y)+0.5),R=(max(P.y,Q.y)+0.5);e[(int)(P.x+0.5)].push_back({L,R,-1});}
        }
        for(int i=1;i<=q;i++){
            pt P=qp[i],Q=qq[i];
            if(dcmp(P.x-Q.x)==0){int L=(min(P.y,Q.y)+0.5),R=(max(P.y,Q.y)+0.5);re[(int)(P.x+0.5)].push_back({L,R,i});}
        }
        for(int i=0;i<=VV;i++){
            for(auto [l,r,id]:e[i])ST::modify(1,0,VV,l,r,1);
            for(auto [l,r,id]:re[i])qres[id]|=(ST::query(1,0,VV,l,r)>0);
            for(auto [l,r,id]:e[i])ST::modify(1,0,VV,l,r,-1);
        }
    }
}
unordered_set<int> ST;
bool med;
signed main(){
    cin>>n>>q;
    cerr<<(&mst-&med)/1024.0/1024.0<<endl;
    for(int i=1;i<=n;i++){
        int cx,cy;cin>>cx>>cy;
        a[i].x=cx,a[i].y=cy,mmx=max(mmx,(int)a[i].x),mmn=min(mmn,(int)a[i].x);
        ST.insert(cx*N+cy);
    }
    for(int i=1;i<=q;i++){
        int a,b,c,d;cin>>a>>b>>c>>d;
        qp[i].x=a,qp[i].y=b,qq[i].x=c,qq[i].y=d;
        if(ST.count(a*N+b)||ST.count(c*N+d))qres[i]=1;
        if(qp[i].x>=qq[i].x)swap(qp[i],qq[i]);
        line Q={qp[i],qq[i]};if(qq[i].x<mmn||qp[i].x>mmx)qres[i]=2;
        else Q=getL(Q,mmn,mmx);
        qp[i]=Q.p,qq[i]=Q.q;
    }
    SOLVE3::solve3();SOLVE1::solve1();SOLVE2::solve2();
    for(int i=1;i<=q;i++){
        if(qres[i]==1)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}