CF1781E 题解
前言
终于过了。感觉我太菜了,这道题目做了将近 $4$ 个来小时,前面 $1.5$ 时,后面 $2.5$ 时(不过至少是独立做出来的)。
我的做法思维难度不怎么大,但是如果不注意封装函数的话那代码的长度会加大。
思路
首先,抓住特殊性质:只有 $2$ 行。
然后我们通过手推样例发现面积和是这些矩形面积的并。
因为我们考虑完全包含的情况那么里面一定是可以不要的,那么再经过思考发现其他矩形和他有相交的地方一定是边缘,必定有一个可以丢弃掉。
就比如说分类讨论可以解决:
-
高一行的和高两行的的相交
在高一行的里面去掉高一行的那个矩形与当前高两行的重复部分。
-
两个高两行的相交
任取一个删去相交部分即可。
-
两个同一行的也是高一行的相交
任取一个删去相交部分即可。
那么我们思考这道题的难点——方案。
你觉得按上面的方法能过吗?你的这个过程很可能要执行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;
}