2018-2019 Pacific Northwest Regional (Div. 1) F Rectangles(线段树扫描线)

题目链接

题意: 矩形覆盖面积奇数次的面积和

思路: 线段树节点每次更新只用看其覆盖奇数次还是偶数次,反转一下即可!!节点的权值也要反转,当前区间长度-上次区间权值 即为节点反转后的权值。仔细想一下即可。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define lson (rt<<1)
#define rson ((rt<<1)|1)
#define Mid ((L+R)>>1)
const int MAXN=201000;
struct pos
{
    int l,r;
    int h,f;
}p[MAXN];

struct node
{
    int lazy;
    int sum;    //边的长度
}tree[MAXN<<2];
int x[MAXN];
int n;

bool cmp(pos a,pos b)
{
    return a.h < b.h;
}

void build(int rt,int L,int R)
{
    tree[rt].sum=0;
    tree[rt].lazy=0;
    if(L == R)  return ;
    build(lson,L,Mid);
    build(rson,Mid+1,R);
}

void pushup(int rt,int L,int R)
{
    tree[rt].sum=tree[lson].sum+tree[rson].sum;
    return ;
}

void pushdown(int rt,int L,int R)
{
    if(tree[rt].lazy){
        tree[lson].sum=x[Mid]-x[L-1]-tree[lson].sum;
        tree[rson].sum=x[R]-x[Mid]-tree[rson].sum;
        tree[lson].lazy^=1;
        tree[rson].lazy^=1;
        tree[rt].lazy=0;
        return ;
    }
}

void update(int rt,int L,int R,int l,int r,int v)
{
    if(l<=L&&R<=r){
        tree[rt].lazy^=1;
        tree[rt].sum=x[R]-x[L-1]-tree[rt].sum;  //每一个节点i的边长都是x[i]-x[i-1]
        return ;
    }
    pushdown(rt,L,R);
    if(l<=Mid)   update(lson,L,Mid,l,r,v);
    if(Mid<r)   update(rson,Mid+1,R,l,r,v);
    pushup(rt,L,R);
}

int main()
{
    int tot=1;
    scanf("%d",&n);
    for(int i=0;i<n;i++){
        int x1,x2,y1,y2;
        scanf("%d%d%d%d",&x1,&y1,&x2,&y2);//输入一个矩形
        pos &t1 = p[tot];pos &t2 = p[1+tot];
        t1.l = t2.l = x1,t1.r = t2.r = x2;
        t1.h = y1;t1.f = 1;
        t2.h = y2;t2.f = -1;
        x[tot] = x1;x[tot+1] = x2;
        tot += 2;
    }
    sort(p+1,p+tot,cmp);//边按高度从小到大排序(自下而上扫描)
    sort(x+1,x+tot);

    int k = 1;
    for (int i = 2;i < tot;++i)
        if (x[i] != x[i-1]) x[++k] = x[i];//去重
    build(1,1,k);
    ll ans=0;
    for(int i=1;i<tot-1;i++){
        int l = lower_bound(x+1,x+k,p[i].l) - x;//在横坐标数组里找到这条边的位置
        int r = lower_bound(x+1,x+k,p[i].r) - x ;
        update(1,1,k,l+1,r,p[i].f); //l+1是将边的长度转换为节点的形式!!
        ans+=1ll*tree[1].sum*(p[i+1].h-p[i].h);
    }
    printf("%lld\n",ans);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值