题解:P8734 [蓝桥杯 2020 国 A] 奇偶覆盖
link: P8734 [蓝桥杯 2020 国 A] 奇偶覆盖
挺好一道题。
矩形覆盖问题,第一时间就想到了扫描线。
再分析题意,朴素的想法是建立一颗线段树,维护 \(0\) / 奇 / 偶 ( \(\geqslant2\) ) 分别的个数,但这其实不好转移(即 add/del 时,三类数的变化)
然后发现,只维护 奇 / 偶 的个数是好做的。
知道奇数的个数后,只需要用总面积相减就可以了,而总面积就是矩形面积并。
于是我们做两遍扫描线:
- 维护 奇 / 偶 的个数。每次
upd时打rev-tag,具体来说,rev-tag使cnt[u] = r - l + 1 - cnt[u] - 求取矩形面积并 P5490 【模板】扫描线 & 矩形面积并
下面贴出两颗线段树:
// 奇偶统计
namespace Sgt1 {
#define mid ((l + r) >> 1)
void updrev(int& u, int l, int r) {
if(!u) u = ++tot;
tag[u] ^= 1;
cnt[u] = (r - l + 1) - cnt[u];
}
void down(int u, int l, int r) {
if(tag[u]) {
updrev(chl[u][0], l, mid);
updrev(chl[u][1], mid + 1, r);
tag[u] = 0;
}
}
void up(int u) {
cnt[u] = cnt[chl[u][0]] + cnt[chl[u][1]];
}
void upd(int& u, int l, int r, int L, int R) {
if(!u) u = ++tot;
if(L <= l && r <= R) {
updrev(u, l, r);
return ;
}
down(u, l, r);
if(L <= mid) upd(chl[u][0], l, mid, L, R);
if(R > mid) upd(chl[u][1], mid + 1, r, L, R);
up(u);
}
#undef mid
}
// 矩形面积并 -> - 奇 = 偶的面积
namespace Sgt2 {
#define mid ((l + r) >> 1)
void up(int u, int l, int r) {
if(tag[u]) cnt[u] = r - l + 1;
else cnt[u] = cnt[chl[u][0]] + cnt[chl[u][1]];
}
void upd(int& u, int l, int r, int L, int R, int f) {
if(!u) u = ++tot;
if(L <= l && r <= R) {
tag[u] += f;
up(u, l, r);
return ;
}
if(L <= mid) upd(chl[u][0], l, mid, L, R, f);
if(R > mid) upd(chl[u][1], mid + 1, r, L, R, f);
up(u, l, r);
}
#undef mid
}
考试时写的动态开点,卡空间是无法通过的。
离散化就交给你们了~
本文来自博客园,作者:CloudDreamLaker,转载请注明原文链接:https://www.cnblogs.com/CloudDreamLake/articles/18363650/tutP8734

浙公网安备 33010602011771号