CF1781E 题解

前言

终于过了。感觉我太菜了,这道题目做了将近 $4$ 个来小时,前面 $1.5$ 时,后面 $2.5$ 时(不过至少是独立做出来的)。

我的做法思维难度不怎么大,但是如果不注意封装函数的话那代码的长度会加大。

思路

首先,抓住特殊性质:只有 $2$ 行。

然后我们通过手推样例发现面积和是这些矩形面积的并。

因为我们考虑完全包含的情况那么里面一定是可以不要的,那么再经过思考发现其他矩形和他有相交的地方一定是边缘,必定有一个可以丢弃掉。

就比如说分类讨论可以解决:

  1. 高一行的和高两行的的相交

    在高一行的里面去掉高一行的那个矩形与当前高两行的重复部分。

  2. 两个高两行的相交

    任取一个删去相交部分即可。

  3. 两个同一行的也是高一行的相交

    任取一个删去相交部分即可。

那么我们思考这道题的难点——方案。

你觉得按上面的方法能过吗?你的这个过程很可能要执行n这个级别的次数次甚至更多,而每次是 $O(n)$ 的,会不会超时想想就知道了。

一看就是构造题,我们要去用一种方法构造一种方案!!!

于是我们可以把高一行且同一行的重复部分先去掉,再把高两行的矩形之间的重复也去了,然后我们又分别处理两行,只是把高两行的也加入当前这行的矩形队列里。对于处理每一行,我们不难发现是高两行的矩形要优先保留,因为他的重叠部分如果去掉了,可能会对另外一行的贡献产生影响。如果还不清楚可以看图(蓝色为高两行的矩形,绿色为与其重叠的矩形,紫色为其他矩形):

所以额外再记录一个答案数组即可。注意可以封装函数以缩短码量。

代码

#include <bits/stdc++.h>
#define ll long long
#define L(i, a, b) for(int i = a; i <= b; i++)
#define R(i, a, b) for(int i = a; i >= b; i--)
using namespace std;
const int N = 2e5 + 10;
struct A{
    int u, l, d, r, i, t;
}a[N], b[N], c[N], ans[N]; 
int n, la, lb, lc, t; ll sum;
bool cmp(A x, A y){return (x.r == y.r)? x.l > y.l : x.r < y.r;}
int Dispose(int l, A d[], int typ = 3){
    vector<A> v;
    if(l) v.push_back(d[1]);
    L(i, 2, l){
        int id = (int)(v.size() - 1);
        for(; id >= 0; id--){
            if(d[i].l <= v[id].l){
                if(typ == 3) ans[v[id].i].u = 3;
                else if(typ == 2) ans[v[id].i].d--;
                else ans[v[id].i].u++;
                v.pop_back();
            }
            else break;
        }
        if(id >= 0 && d[i].l <= v[id].r){
            if(d[i].t == 3)
                ans[v[id].i].r = v[id].r = d[i].l - 1;
            else ans[d[i].i].l = d[i].l = v[id].r + 1;
        }
        if(d[i].i) v.push_back(d[i]);
    }
    t = 0; L(i, 0, (int)(v.size() - 1)) d[++t] = v[i];
    return t;
}
void Solve(){
    scanf("%d", &n);
    sum = la = lb = lc = 0;
    L(i, 1, n){
        int u, l, d, r;
        scanf("%d%d%d%d", &u, &l, &d, &r);
        ans[i] = {u, l, d, r, i};
        if(u == 1 && d == 1) a[++la] = {u, l, d, r, i, 1};
        else if(u == 2 && d == 2) b[++lb] = {u, l, d, r, i, 2};
        else c[++lc] = {u, l, d, r, i, 3};
    }
    sort(a + 1, a + la + 1, cmp);
    sort(b + 1, b + lb + 1, cmp);
    sort(c + 1, c + lc + 1, cmp);
    la = Dispose(la, a, 1);
    lb = Dispose(lb, b, 2);
    lc = Dispose(lc, c);
    L(i, 1, lc) a[la + i] = b[lb + i] = c[i];
    sort(a + 1, a + la + lc + 1, cmp);
    sort(b + 1, b + lb + lc + 1, cmp);
    int s = Dispose(la + lc, a, 1); s = Dispose(lb + lc, b, 2);
    L(i, 1, n){
        if(ans[i].u > ans[i].d || ans[i].l > ans[i].r){
            ans[i] = {}; continue;
        }
        sum += (ans[i].d - ans[i].u + 1) * (ans[i].r - ans[i].l + 1);
    }
    printf("%d\n", sum);
    L(i, 1, n)
        printf("%d %d %d %d\n", ans[i].u, ans[i].l, ans[i].d, ans[i].r);
}
int main(){
    int T; scanf("%d", &T);
    while(T--) Solve();
    return 0;
}
posted @ 2023-01-25 17:33  徐子洋  阅读(6)  评论(0)    收藏  举报  来源