• CodeForces 524E. Rooks and Rectangles(线段树)(排序解决偏序)


    题意:给出一张地图,一个n * m的方格图。
    给出K个监督者的位置,每个监督者可以监视他所处的行和列上的每一格位置。
    一个区域被认为是安全的,当且仅当区域中的每一个方格都被监督者监视着。(区域外的监督者无法监视这个区域中的方格)

    现在你需要回答q次询问。
    每次询问包含四个数字x1 y1 x2 y2表示区域的左上角方格的坐标,右下角方格的坐标。
    如果询问区域是安全的,那么输出"YES",否则输出"NO"。

    分析:因为数据范围很大,不能暴力预处理。因此,需要考虑别的算法,比如数据结构,我们考虑能否优化成(o(nlogn))之类的算法,对于一个区域,我们要想这个区域内的每行每列都被监视到,可以从不同的方面考虑,把行和列分开来考虑,我们把骑士的x坐标从小到大排序,直到骑士的x坐标<= 当前询问的右下角x2坐标,再用一个数据结构维护y轴,每个点上再维护插入的骑士的x坐标的最小值,这样,当我们查询一个范围内([y1, y2])的最小值时,如果这个最小值>=x1,那么这个区间的每行每列都会被监视到。(为什么不需要判断<=x2这种情况呢),因为我们是从小到大单点修改的,如果这个点没有被修改过,那么整个区间的最小值就会=0。我们还要考虑翻转x轴和y轴的情况,这个可以画图,我们只要满足两者之一即可。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    
    using namespace std;
    const int N = 200005;
    const int M = 100005;
    const int inf = 0x3f3f3f3f;
    struct Node
    {
    	int x, y;
    }kni[N];
    
    struct query
    {
    	int x1, y1, x2, y2;
    	int id;
    }que[N];
    
    int res[N];
    int n, m, k, q;
    
    bool cmp(const Node& lhs, const Node& rhs)
    {
    	return lhs.x < rhs.x;
    }
    
    bool cmp1(const query& lhs, const query& rhs)
    {
    	return lhs.x2 < rhs.x2;
    }
    
    struct seg
    {
    	int val;
    }tr[M * 4];
    
    void modify(int u, int l, int r, int pos, int val)
    {
    	if (l == r)
    	{
    		tr[u].val = val;
    		return;
    	}
    	int mid = l + r >> 1;
    	if (pos <= mid) modify(u << 1, l, mid, pos, val);
    	else modify(u << 1 | 1, mid + 1, r, pos, val);
    	tr[u].val = min(tr[u << 1].val, tr[u << 1 | 1].val);
    }
    
    int Query(int u, int L, int R, int l, int r)
    {
    	if (l <= L && r >= R)
    	{
    		return tr[u].val;
    	}
    	int mid = L + R >> 1;
    	int res = inf;
    	if (l <= mid) res = min(res, Query(u << 1, L, mid, l, r));
    	if (r > mid) res = min(res, Query(u << 1 | 1, mid + 1, R, l, r));
    	return res;
    }
    
    void cal()
    {
    	memset(tr, 0, sizeof tr);
    	int cnt = 0;
    	for (int i = 1; i <= q; ++i)
    	{
    		while (cnt <= k && kni[cnt].x <= que[i].x2)
    		{
    			modify(1, 1, m, kni[cnt].y, kni[cnt].x);
    			++cnt;
    		}
    		if (Query(1, 1, m, que[i].y1, que[i].y2) >= que[i].x1)
    			res[que[i].id] = 1;
    	}
    }
    
    void Swap()
    {
    	swap(n, m);
    	for (int i = 1; i <= k; ++i)
    		swap(kni[i].x, kni[i].y);
    
    	sort(kni + 1, kni + k + 1, cmp);
    
    	for (int i = 1; i <= q; ++i)
    	{
    		swap(que[i].x1, que[i].y1);
    		swap(que[i].x2, que[i].y2);
    	}
    	sort(que + 1, que + q + 1, cmp1);
    }
    
    int main()
    {	
    	scanf("%d%d%d%d", &n, &m, &k, &q);
    
    	//int x, y;
    	for (int i = 1; i <= k; ++i)
    	{
    		scanf("%d%d", &kni[i].x, &kni[i].y);
    	}
    	sort(kni + 1, kni + k + 1, cmp);
    	for (int i = 1; i <= q; ++i)
    	{
    		scanf("%d%d%d%d", &que[i].x1, &que[i].y1, &que[i].x2, &que[i].y2);
    		que[i].id = i;
    	}
    	sort(que + 1, que + q + 1, cmp1);
    	cal();
    	Swap();
    	cal();
    
    	for (int i = 1; i <= q; ++i)
    	{
    		if (res[i] == 1)
    			puts("YES");
    		else
    			puts("NO");
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Leetcode#117 Populating Next Right Pointers in Each Node II
    Leetcode#123 Best Time to Buy and Sell Stock III
    获取文件大小的方法
    内存映射
    git patch
    git cherry-pick
    关于extern的说明
    Linux如何查看与/dev/input目录下的event对应的设备
    如何在Linux下统计高速网络中的流量
    [: ==: unary operator expected 解决方法
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/13308824.html
Copyright © 2020-2023  润新知