Gym F Rectangles (线段树,扫描线。)

 

求相交面积 为奇数次的面积总和。

就是随便改一下原来扫描线的代码。 ,

 

 

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5;
struct node{
    int y,x1,x2;
    int flag;
    bool operator < (const node &now) const {
        return y < now.y;
    }
}g[N];
struct segtree{
    int ll,rr;
    long long w;
    int l,r,a,b,c,cover;
    int cal_mid(){
        return (a + b) / 2;
    }
}f[N*2];
int t,n,zz;
int x[N],xx,yy;
void build(int p, int a, int b){
    f[p].a = a; f[p].b = b;
    f[p].ll = x[a]; f[p].rr = x[b];
    f[p].w = f[p].cover = f[p].c =0;
    if (a + 1 == b) return;
    int m = f[p].cal_mid();
    t++; f[p].l = t; build(t,a,m);
    t++; f[p].r = t; build(t,m,b);
    return;
}
void pushup(int p){
    if (f[p].a + 1 == f[p].b) {
        if (f[p].cover % 2 == 1) f[p].w = f[p].rr - f[p].ll;
        else f[p].w = 0;
    }
    else{
        f[p].w = f[f[p].l].w + f[f[p].r].w;
        if (f[p].cover % 2 == 1)
            f[p].w = (f[p].rr - f[p].ll) - f[p].w;           
    } 
        return;
}
void Insert(int p){
    if ((xx <= f[p].ll && yy >= f[p].rr ) || f[p].a + 1 == f[p].b ){
        f[p].cover = f[p].cover + zz;
        pushup(p);
        return;
    }
    if (xx < f[f[p].l].rr) Insert(f[p].l);
    if (yy > f[f[p].r].ll) Insert(f[p].r); //    这里就要根据实际情况来判断了。
    pushup(p);
    return;
}
int main() {
    scanf("%d",&n);
        int x1,x2,y1,y2;
        int tt = 1; 
        for (int i = 1; i <= n; i++){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            g[tt].x1 = x1; g[tt].x2 = x2; g[tt].flag = 1; x[tt] = x1; g[tt++].y = y1;
            g[tt].x1 = x1; g[tt].x2 = x2; g[tt].flag = -1; x[tt] = x2; g[tt++].y = y2;
        }
        sort(g + 1, g + tt); //离散化
        sort(x + 1, x + tt); tt--;
        t = 1;
        build(1,1,tt); //建树, 1 到 n 这种求区间长度的线段树,暂且理解为全部都是闭区间吧。
        xx = g[1].x1; yy = g[1].x2; zz = 1;
        Insert(1);
        long long ans = 0;
        for (int i = 2; i <= tt; i++){
            xx = g[i].x1; yy = g[i].x2; zz = g[i].flag;
            ans += 1ll*f[1].w * (g[i].y - g[i - 1].y);
            // printf("%d %d %d\n",i,f[1].w,ans);
            Insert(1);
            // printf("\n");
        }
        printf("%lld\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值