[P5490] 【模板】扫描线 - 线段树

\(n\) 个矩形的面积并

Solution

将矩形转化为 \(y_1\) 位置的 + 修改 和 \(y_2\) 位置的 - 修改。然后按照 \(+y\) 顺序依次处理所有的修改,到达的一个新的位置就算一下上一段的总贡献。

至于线段树,要么对 \(x\) 坐标离散化,要么动态开点。 我觉得后者比较快乐。

注意这里的标记没有必要下传

#include 
using namespace std;

const int N = 5000005;

struct event{
    int x1,x2,y,z;
    bool operator < (const event &b) {
        return y < b.y;
    }
} e[N];

int n,m,a[N],cnt[N],tag[N],ch[N][2],ind=1;

void pushup(int p,int l,int r) {
    if(p==0) return;
    a[0]=0;
    if(cnt[p]) a[p]=r-l+1;
    else a[p]=a[ch[p][0]]+a[ch[p][1]];
}

void modify(int p,int l,int r,int ql,int qr,int c) {
    if(l>qr||r=ql&&r<=qr) {
        cnt[p]+=c;
        pushup(p,l,r);
    }
    else {
        if(ch[p][0]==0) ch[p][0]=++ind;
        if(ch[p][1]==0) ch[p][1]=++ind;
        modify(ch[p][0],l,(l+r)/2,ql,qr,c);
        modify(ch[p][1],(l+r)/2+1,r,ql,qr,c);
        pushup(p,l,r);
    }
}

signed main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
        ++x1; ++x2;
        e[i*2-1]=(event){x1,x2,y1,1};
        e[i*2]=(event){x1,x2,y2,-1};
        m=max(m,x2);
    }
    sort(e+1,e+2*n+1);
    long long ans=0;
    for(int i=1;i<=2*n;i++) {
        if(e[i].y!=e[i-1].y) ans+=1ll*a[1]*(e[i].y-e[i-1].y);
        modify(1,1,m,e[i].x1+1,e[i].x2,e[i].z);
    }
    cout<

你可能感兴趣的:([P5490] 【模板】扫描线 - 线段树)