51Nod 1559 车和矩形

线段树+扫描线

考虑符合题意的充要条件,是每一行每一列都有一个车?并不,显然可以构造出一行没有的合法情况,但此时必须是每一列都有车,因此充要条件是每一行都有车或每一列都有车。

两种情况分开来做,考虑怎么判断每一行都有车。扫描线,按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();
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值