题解:P8734 [蓝桥杯 2020 国 A] 奇偶覆盖

link: P8734 [蓝桥杯 2020 国 A] 奇偶覆盖

挺好一道题。

矩形覆盖问题,第一时间就想到了扫描线。

再分析题意,朴素的想法是建立一颗线段树,维护 \(0\) / 奇 / 偶 ( \(\geqslant2\) ) 分别的个数,但这其实不好转移(即 add/del 时,三类数的变化)

然后发现,只维护 奇 / 偶 的个数是好做的。
知道奇数的个数后,只需要用总面积相减就可以了,而总面积就是矩形面积并。

于是我们做两遍扫描线:

下面贴出两颗线段树:

// 奇偶统计
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
}

考试时写的动态开点,卡空间是无法通过的。
离散化就交给你们了~

posted @ 2024-08-16 21:26  CloudDreamLaker  阅读(46)  评论(0)    收藏  举报