蓝桥杯2020决赛:试题 I 奇偶覆盖

原题

如果不考虑奇偶性,其实就是扫描线的板子。
考虑如何处理奇偶:
首先在线段树存两个变量 \(len_1\) 以及 \(len_2\),分别表示奇长度和偶长度。再用 \(sum\) 记录当前两个端点之间被覆盖了多少次。
然而我们无法直接获得每一个子区间的具体覆盖数目。所以从奇偶性的特点方面入手。

假设当前区间被覆盖了奇数次,那么:
\(len_2 = 子区间len_1\)
\(len_1 = 子区间len_2 + 可能未被覆盖到的长度\)

\(len_1\)无法直接求,但是可以用总区间长度减去\(len_2\)得到。

代码:

#include <bits/stdc++.h>
using namespace std;
#define N 100010
#define ll long long
#define y1 abdbsdhuhdwiuoh
#define int long long

template <class T>
inline T read(T& a){
    T x = 0, s = 1;
    char c = getchar(); 
    while(!isdigit(c)){ if(c == '-') s = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + (c ^ '0'); c=  getchar(); }
    a = x * s; 
    return a; 
}

int n; 
struct Line{
    int x, y, h, flag; 
} L[N << 1]; 

int X[N << 1]; // 离散化坐标

struct Segment_tree{
    struct node{
        int sum, len1, len2; 
    }  t[N << 4]; // 多乘一个2

    #define lson (o<<1)
    #define rson (o<<1|1)

    inline void pushup(int o, int l, int r){
        if(t[o].sum){
            if(t[o].sum){
                if(t[o].sum % 2 == 1){
                    if(l == r){
                        t[o].len1 = X[r + 1] - X[l]; 
                        t[o].len2 = 0; 
                    }
                    else{
                        t[o].len2 = t[lson].len1 + t[rson].len1; 
                        t[o].len1 = X[r + 1] - X[l] - t[o].len2; 
                    }
                }
                else{
                    if(l == r){
                        t[o].len2 = X[r + 1] - X[l]; 
                        t[o].len1 = 0; 
                    }
                    else{
                        t[o].len1 = t[lson].len1 + t[rson].len1; 
                        t[o].len2 = X[r + 1] - X[l] - t[o].len1; 
                    }
                }
            }
        }
        else{
            if(l == r) t[o].len1 = t[o].len2 = 0;  // 不特判的话要多加一层
            else {
                t[o].len1 = t[lson].len1 + t[rson].len1; 
                t[o].len2 = t[lson].len2 + t[rson].len2; 
            }
        }
        return ; 
    }

    void build(int o, int l, int r){
        t[o].sum = t[o].len1 = t[o].len2 = 0; 
        if(l == r) return ; 
        int mid = l + r >> 1;
        build(lson, l, mid); 
        build(rson, mid + 1, r); 
        pushup(o, l, r); 
        return ; 
    }

    void update(int o, int l, int r, int L, int R, int k){
        if(X[l] >= R || X[r + 1] <= L) return ; // 端点相等也是不够的。因为表示的是右侧一段区间,端点没有意义。
        if(X[l] >= L && X[r + 1] <= R){
            t[o].sum += k; 
            pushup(o, l, r); 
            return ; 
        }
        int mid = l + r >> 1; 
        update(lson, l, mid, L, R, k); 
        update(rson, mid + 1, r, L, R, k); 
        pushup(o, l, r); 
        return ; 
    }

} tree; 

signed main(){
    read(n); 
    for(int i = 1; i <= n; i++){
        int x1, y1, x2, y2; 
        read(x1), read(y1), read(x2), read(y2); 
        L[i * 2 - 1] = (Line){x1, x2, y1, 1}; 
        L[i * 2] = (Line){x1, x2, y2, -1}; 
        X[i * 2 - 1] = x1; 
        X[i * 2] = x2; 
    }
    n <<= 1ll;
    sort(X + 1, X + n + 1); 
    int tot = unique(X + 1, X + n + 1) - X - 1; 
    sort(L + 1, L + n + 1, [](Line a, Line b){
        return a.h < b.h; 
    }); 

    tree.build(1, 1, tot - 1); 
    int ans1 = 0, ans2 = 0; 
    for(int i = 1; i < n; i++){
        tree.update(1, 1, tot - 1, L[i].x, L[i].y, L[i].flag); 
        ans1 += tree.t[1].len1 * (L[i+1].h - L[i].h); 
        ans2 += tree.t[1].len2 * (L[i + 1].h - L[i].h); 
    }
    cout << ans1 << endl << ans2 << endl; 
    return 0; 
}
posted @ 2024-03-03 18:07  雪之下,树之旁  阅读(21)  评论(0编辑  收藏  举报