题目链接:http://codeforces.com/contest/1028/problem/C

这道题的题目大意是:给你n个矩形(左上角的坐标,右下角坐标),让你输出一个点,让至少n-1个矩形包含这个点,因为题目保证至少存在一个这样的点,所要我们排除一个矩形,再求剩下n-1个矩形的的相交矩形,在输出其中一个点就行了。我们可以枚举要排除的矩形,再求剩下(n-1)的矩形的相交矩形,但是复杂度为O(n^2),会超时。那我们有没有办法排除一个矩形时,快速求解剩下(n-1)的矩形的相交矩形呢?

我们先来看两个矩形相交的情况

从图中就可以看出相交矩形的左上角和右下角坐标的求法如下:

//左上角坐标(i, j), 右下角坐标(x, y)
 
//矩形1(i1, j1)(x1, y1), 矩形2(i2, j2)(x2, y2)
相交矩形的坐标
i =  max(i1, i2);
j =  max(j1, j2);
x =  min(x1, x2);
y =  min(y1, y2);

如果两个矩形不相交,那么i, j, x, y会出现什么情况,简单模拟一下就知道了。

if(i<x||j<y)
	printf("不相交\n");
else if(i==x&&j==y)
	printf("相交与一点\n");
else if(i==x||j==y)
	printf("相交与一条直线\n");
else
	printf("存在相交矩形\n");

如果有3个矩形,4个矩形,…,n个矩形怎么办?

只要把相交矩形再与第3个矩形在求相交矩形,在与第4个矩形求相交矩形,…,在与第n个矩形求相交矩形就行了。

我们学会了解决n个相交矩形的问题,那么我们把问题改一下:给你n个矩形,并进行n次操作,每次操作输入m, i, j, x, y把第m个矩形的坐标修改(修改会保存)为(i, j),(x, y)。在让在修改后都求这n个矩形的相交矩形,如果每次修改后,我们都重新开始第1个矩形相交一直到第n个矩形相交求一遍,时间复杂度为O(n^n), 如果n数据为10^5,或者更大,那么这道题肯定超时。

我们再看看刚才求两个矩形相交的求法:

//左上角坐标(i, j), 右下角坐标(x, y)
 
//矩形1(i1, j1)(x1, y1), 矩形2(i2, j2)(x2, y2)
相交矩形的坐标
i =  max(i1, i2);
j =  max(j1, j2);
x =  min(x1, x2);
y =  min(y1, y2);

如果求n个,只要把相交矩形当做第一个矩形,进行n-1次循环就行了,在这n次循环中

//相交矩形的坐标
i =  max(i1, i2, i3, ... , in);
j =  max(j1, j2, j3, ... , jn);
x =  min(x1, x2, x3, ... , xn);
y =  min(y1, y2, y3, ... , yn);

看到这就应该有思路了
相交矩形的 i, j, x, y 之间没有任何关系。那么修改一个矩形我们只有修改i, j, x, y中的一个元素再求 i, j, x, y; 那么我们只要把n个矩形的i, j, x, y分开保存在4个数组就就行了。每次修改后,我们只要修改i[m], j[m], x[m], yu[m], 在求相应最大最小值就行了。当时求最大最小值的复杂度也为n,那么复杂度没有变。

看到,可能有的人有疑问,这个每次修改后,只要把修改的值与之前的最值进行比较就行了。复杂度为O(1), 听着好像没有问题, 但是如果修改的就是之前的最值,那么就要重新找一次最值

当然我们可以用快速排序把查找最值复杂度降O(log n),我们也可以用STL中的平衡二叉树容器pultiset 复杂度也为O(log n)。这道题完美的理论AC。

我们再来看文章开始的问题那么这道题也已经理论AC了, 为了熟悉STL模板我就用pultiset了。

思考:我这篇博客是看了https://blog.csdn.net/xianpingping/article/details/82193032的博客写的,这位大佬写得太简略了,代码只有17行,看不到他的思路。自己看看画画,又在纸上调试了一个小时,才明白这道题的思路。

AC代码如下:

#include<bits/stdc++.h>
using namespace std;

#define N 150000
int a[N][4];
multiset<int> s[4];

int main()
{
    int n;
    scanf("%d",&n);

    for(int i=0;i<n;i++)//读入矩形
    {
        for(int j=0;j<4;j++)
        {
            scanf("%d",&a[i][j]);
            s[j].insert(a[i][j]);
        }
    }

    for(int i=0;i<n;i++)//枚举删除的矩形
    {
        for(int j=0;j<4;j++)//删除矩形
        {
            //不用s[j].erase(a[i][j])
            //会删除所有的a[i][j]
            s[j].erase(s[j].find(a[i][j]));
        }

        //满足i<=x&&j<=y,则n-1个矩形至少交于一点
        if(*s[0].rbegin()<=*s[2].begin()&&*s[1].rbegin()<=*s[3].begin())
        {
            cout<<*s[0].rbegin()<<' '<<*s[1].rbegin()<<endl;
            break;
        }

        //如果删除这个矩形不满足
        //则恢复这个矩形,枚举下一个删除的矩形
        for(int j=0;j<4;j++)
        {
            s[j].insert(a[i][j]);
        }

    }

    return 0;
}