4e5大小的线段树来喽!怎么,都RE了? Luogu P3875 [TJOI2010]被污染的河流

P3875 [TJOI2010]被污染的河流 题解

本来是为了改昨天的题,发现扫描线基本上都忘了,打算找个扫描线练练手,结果打的有来有回的。

解析

污染区域是以河流为中线的一块矩形,可能生病的社区数量就是这些矩形的面积并。

很显然是扫描线,线段树维护。

存储每个矩形左,右边界,左边界赋1,右边界赋-1 ,把线段排序,再依次处理每一条线段。

整体来说挺板子的,需要注意一些小细节。

河流起始位置和结束位置的坐标不一定先左后右,先下后上,所以要swap一下。

x值相等时,河流为纵向流向,左边界的x值为 x - 1,右边界的x值为 x + 1。

y值相等时,河流为横向流向,左,右边界的yl(下方的端点)值为 y - 1,yl(上方的端点)值为 y + 1。

因为有 - 1 和 + 1 的操作,所以端点会出现值为 0 或 1000001 的情况,线段树初始化的时候要注意。

最重要的是,4e5 大小的线段树会RE,所以开大一点。

Code

#include<cstdio>
#include<algorithm>

using namespace std;

const int MAXN = 1e4 + 10, MAXM = 2e5 + 10;
int n, sum, maxr;

struct Line{
    int x;
    int yh, yl;
    int sit;
}line[MAXM << 1];

inline bool cmp(const Line &a, const Line &b){
    return a.x < b.x;
}

struct Segment_Tree{
    struct Tree{
        int l, r;
        int len;
        int cnt;
    }tr[MAXM << 2];

    inline int lson(int rt){
        return rt << 1;
    }

    inline int rson(int rt){
        return rt << 1 | 1;
    }

    inline void Pushup(int rt){
        if(tr[rt].cnt)
            tr[rt].len = tr[rt].r - tr[rt].l + 1;
        else   
            tr[rt].len = tr[lson(rt)].len + tr[rson(rt)].len;
    }

    void Build(int rt, int l, int r){
        tr[rt].l = l;
        tr[rt].r = r;
        tr[rt].len = 0;
        tr[rt].cnt = 0;

        if(l == r)
            return;
        
        int mid = (l + r) >> 1;
        Build(lson(rt), l, mid);
        Build(rson(rt), mid + 1, r);
    }

    void Update(int rt, int l, int r, int data){
        if(tr[rt].l >= l && tr[rt].r <= r){
            tr[rt].cnt += data;

            Pushup(rt);
            return;
        }

        int mid = (tr[rt].l + tr[rt].r) >> 1;
        if(l <= mid) Update(lson(rt), l, r, data);
        if(r > mid) Update(rson(rt), l, r, data);

        Pushup(rt);
    }
}S;

inline int read(){
    int x = 0, f = 1;
    char c = getchar();

    while(c < '0' || c > '9'){
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9'){
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }

    return x * f;
}

int main(){
    n = read();
    for(register int i = 1; i <= n; i++){
        int x1, y1, x2, y2;
        x1 = read(), y1 = read(), x2 = read(), y2 = read();
        
        if(x1 > x2) swap(x1, x2);
        if(y1 > y2) swap(y1, y2);

        if(x1 == x2){
            line[(i << 1) - 1].x = x1 - 1, line[(i << 1)].x = x2 + 1;
            line[(i << 1) - 1].yl = line[(i << 1)].yl = y1;
            line[(i << 1) - 1].yh = line[(i << 1)].yh = y2;
            line[(i << 1) - 1].sit = 1;
            line[(i << 1)].sit = -1;
        }
        else if(y1 == y2){
            line[(i << 1) - 1].x = x1, line[(i << 1)].x = x2;
            line[(i << 1) - 1].yl = line[(i << 1)].yl = y1 - 1;
            line[(i << 1) - 1].yh = line[(i << 1)].yh = y2 + 1; 
            line[(i << 1) - 1].sit = 1;
            line[(i << 1)].sit = -1;
        }
    }

    n <<= 1;
    sort(line + 1, line + 1 + n, cmp);
    S.Build(1, 0, 100001);

    for(register int i = 1; i < n; i++){
        S.Update(1, line[i].yl, line[i].yh - 1, line[i].sit);
        sum += S.tr[1].len * (line[i + 1].x - line[i].x);
    }

    printf("%d\n", sum);

    return 0;
}
posted @ 2022-08-12 21:26  TSTYFST  阅读(35)  评论(0编辑  收藏  举报