线段树+扫描线
考虑符合题意的充要条件,是每一行每一列都有一个车?并不,显然可以构造出一行没有的合法情况,但此时必须是每一列都有车,因此充要条件是每一行都有车或每一列都有车。
两种情况分开来做,考虑怎么判断每一行都有车。扫描线,按y轴排序,每一个矩形就相当于区间询问,只需判断区间里此时每一行的最近的车中最远的在哪,如果落在矩形外就不行了,于是只需求区间最小值。
#include<cstdio>
#include<algorithm>
#define N 200005
using namespace std;
namespace runzhe2000
{
void mswap(int &x, int &y){int t=x;x=y;y=t;}
int read()
{
int r = 0; char c = getchar();
for(; c < '0' || c > '9'; c = getchar());
for(; c >='0' && c <='9'; r = r*10+c-'0', c = getchar());
return r;
}
const int INF = 1<<29;
int n, m, k, q, ans[N], evecnt;
struct event{int x, y, xx, yy, type, id;}eve[N<<1];
bool cmp(event a, event b){return a.y != b.y ? a.y < b.y : a.type > b.type;}
struct seg{int v;}t[N*5];
void build(int x, int l, int r)
{
t[x].v = 0; if(l == r) return; int mid = (l+r)>>1;
build(x<<1,l,mid); build(x<<1|1,mid+1,r);
}
void modif(int x, int l, int r, int p, int v)
{
if(l == r) {t[x].v = v; return;} int mid = (l+r)>>1;
if(p <= mid) modif(x<<1,l,mid,p,v); else modif(x<<1|1,mid+1,r,p,v);
t[x].v = min(t[x<<1].v, t[x<<1|1].v);
}
int query(int x, int l, int r, int ql, int qr)
{
if(ql <= l && r <= qr) return t[x].v; int mid = (l+r)>>1, ret = INF;
if(ql <= mid) ret = min(ret, query(x<<1,l,mid,ql,qr));
if(mid < qr) ret = min(ret, query(x<<1|1,mid+1,r,ql,qr));
return ret;
}
void solve()
{
sort(eve+1, eve+1+evecnt, cmp);
build(1,1,n);
for(int i = 1; i <= evecnt; i++)
{
if(eve[i].type == 1) modif(1,1,n,eve[i].x,eve[i].y);
else if(!ans[eve[i].id]) ans[eve[i].id] = query(1,1,n,eve[i].xx,eve[i].x) >= eve[i].yy;
}
}
void main()
{
n=read(),m=read(),k=read(),q=read();
for(int i = 1; i <= k; i++)
{
event *tmp = &eve[i];
tmp->x=read(),tmp->y=read();
tmp->type = 1;
}
for(int i = 1; i <= q; i++)
{
event *tmp = &eve[i+k];
tmp->xx=read(),tmp->yy=read(),tmp->x=read(),tmp->y=read();
tmp->type = 0; tmp->id = i;
}
evecnt = k+q;
solve();
mswap(n, m);
for(int i = 1; i <= evecnt; i++) mswap(eve[i].x, eve[i].y), mswap(eve[i].xx, eve[i].yy);
solve();
for(int i = 1; i <= q; i++) puts(ans[i] ? "YES" : "NO");
}
}
int main()
{
runzhe2000::main();
}