51Nod - 1559 线段树 + 扫描线
2017-04-07 15:04
316 查看
题意:
题目链接:https://www.51nod.com/onlineJudge/questionCode.html#!problemId=1559波雷卡普有一个n×m大小的棋盘,上面有k个车。他又放了q个矩形在上面。每一个矩形要受到保护。矩形受到保护的意思是对于该矩形内部所有的格子能够被这个矩形内的某个车攻击到或者被占据,和矩形外面的车无关,即矩形外面的车不能攻击到矩形里面。车的位置是固定的。
样例示意图如下:
题意有点坑,要注意这里判断矩形是否安全的时候,只要考虑当前要判断的矩形和所有的车,而不要考虑其他矩形的影响。
思路:
如果理解对了题意,可以很容易想到,一个矩形如果能称得上的是安全的,就等价于这个矩形的每一行都有车或者每一列都有车。这里不妨先考虑每一列都有车,按照示意图,x是列,y是行。矩形左下角顶点为(lx,ly),右上角顶点为(rx,ry)。
这样对于一个矩形,判断每一列是否都有车,其实就相当于一个对于区间[lx,rx]查询,这就容易想到线段树,但是一列可能会有多个车,所以不能用线段树直接保存每个车的纵坐标y。
注意到这样一个事实:对于每个矩形,其实我们只想知道横坐标x在[lx,rx]之间的且纵坐标y比不超过矩形上横边ry的且与ry最接近的车,这样的车的y只要大于等于当前矩形的下横边ly,就说明这个车在矩形中。那么线段树就不需要保存所有的车的位置,只要维护当前小于等于ry的最大的y即可。
1. 将每个车都当作大小为1的矩形,这样把车和矩形放在一起按照ry从小到大排序。
2. 如果当前是车,就更新线段树,让x的位置的值更新为较大的y。
3. 如果当前是矩形,就查询线段树,判断线段树[lx,rx]中的最小值是否大于等于ly。
之所以不判断y和ry的关系是因为之前的排序,保证了当前的线段树中不会有y的值大于ry。
代码:
#include <bits/stdc++.h> using namespace std; #define lson l, m, rt << 1 #define rson m + 1, r, rt << 1 | 1 const int MAXN = 4e5 + 10; const int INF = 0x3f3f3f3f; struct node { int lx, ly, rx, ry, id, type; bool operator < (const node &rhs) const { return ry < rhs.ry || (ry == rhs.ry && type > rhs.type); } } a[MAXN]; struct SegmentTree { int C[MAXN << 2]; void push_up(int rt) { C[rt] = min(C[rt << 1], C[rt << 1 | 1]); } void build(int l, int r, int rt) { C[rt] = 0; if (l == r) return; int m = (l + r) >> 1; build(lson); build(rson); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return C[rt]; int m = (l + r) >> 1, res = INF; if (L <= m) res = min(res, query(L, R, lson)); if (R > m) res = min(res, query(L, R, rson)); return res; } void update(int pos, int val, int l, int r, int rt) { if (l == r) { C[rt] = max(C[rt], val); return; } int m = (l + r) >> 1; if (pos <= m) update(pos, val, lson); else update(pos, val, rson); push_up(rt); } }segtree; bool ans[MAXN]; void solve(int n, int cnt) { sort (a + 1, a + 1 + cnt); segtree.build(1, n, 1); for (int i = 1; i <= cnt; i++) { if (a[i].type == 1) { segtree.update(a[i].rx, a[i].ry, 1, n, 1); } else if (!ans[a[i].id]) { // cout << segtree.query(a[i].lx, a[i].rx, 1, n, 1) << endl; ans[a[i].id] = segtree.query(a[i].lx, a[i].rx, 1, n, 1) >= a[i].ly; } } } inline bool scan_d(int &num) { char in;bool IsN=false; in=getchar(); if(in==EOF) return false; while(in!='-'&&(in<'0'||in>'9')) in=getchar(); if(in=='-'){ IsN=true;num=0;} else num=in-'0'; while(in=getchar(),in>='0'&&in<='9'){ num*=10,num+=in-'0'; } if(IsN) num=-num; return true; } int main() { //freopen("in.txt", "r", stdin); int n, m, k, q; scan_d(n); scan_d(m); scan_d(k); scan_d(q); for (int i = 1; i <= k; i++) { scan_d(a[i].rx); scan_d(a[i].ry); a[i].type = 1; } for (int i = 1; i <= q; i++) { scan_d(a[i + k].lx); scan_d(a[i + k].ly); scan_d(a[i + k].rx); scan_d(a[i + k].ry); a[i + k].id = i; a[i + k].type = 0; } solve(n, k + q); for (int i = 1; i <= k + q; i++) { swap(a[i].lx, a[i].ly); swap(a[i].rx, a[i].ry); } solve(m, k + q); for (int i = 1; i <= q; i++) { if (ans[i]) puts("YES"); else puts("NO"); } return 0; }
相关文章推荐
- 【51nod】1494 选举拉票 扫描线+线段树
- 51nod 1494 选举拉票【贪心】【扫描线】【线段树】
- 51nod 1461 稳定桌【扫描线】【线段树】
- 【51nod】1461 稳定桌 扫描线+线段树
- [51nod 1208] Stars in Your Window(线段树,扫描线)
- 51nod 1206 Picture 矩形周长求并 | 线段树 扫描线
- 51nod 1208 窗上的星星 | 线段树 扫描线
- 51Nod 1672 扫描线 + 线段树/树状数组
- 线段树+扫描线【bzoj1645】[USACO07OPEN]城市的地平线City Horizon
- [扫描线 线段树上二分] BZOJ 4411 [Usaco2016 Feb]Load balancing
- hdu3255 线段树扫描线求体积
- 51nod-1364 最大字典序排列(线段树)
- Poj 1177线段树 离散化 扫描线
- hdu 1556 Color the ball (线段树之扫描线)
- HDU 1542 Atlantis(线段树,离散化,扫描线)
- [HDU] 1542 - Atlantis - 矩形并 - 离散化 - 扫描线 - 线段树
- HDU 1255 覆盖的面积 线段树 扫描线
- zoj zju 3597 Hit the Target! 线段树 扫描线
- 51nod:加农炮(线段树+单调性)
- 51NOD 1631 小鲨鱼在51nod小学 区间线段树