Codeforces 610D 矩形面积并

Codeforces 610D
题目链接:
http://blog.csdn.net/julyana_lin/article/details/7834653
题意:
给n个矩形,宽度均为1,与x或者y中一个轴平行。
矩形可能有覆盖。
求所有矩形覆盖后的面积和。
思路:
有map乱弄的做法,以下采用矩阵面积并。

矩阵面积并 = 线段树 + 扫描线 + 离散化

把矩形分成下边和上边,下边进入事件,上边离开事件。
每条边左右端点进行离散化,具体实现用map和数组都可以。
维护线段树,线段树中每个点的坐标为离散化以后的坐标。
线段树的每个节点存两个值,一个是覆盖的层数,一个是返回的和。

注意:update时为update(L,R-1…),push_up时中第二个条件分支为idx[R+1] - idx[L]
这个下标是表示端点离散化以后,分割成的一个一个小线段的这个线段的左端点。。。更 新的时候也是同一个道理。。。这样表示可以避免由于线段树更新中一些线段没有算到的 情况,比如[1,4]分割成[1,2],[3,4],如果不这样更新就会少算[2,3]这条线段。

本题中我把每个点处理成以它为左下角的小单位矩形。
源码:

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <string>
#include <algorithm>
#include <iostream>
#include <vector>
#include <map>
using namespace std;
const int MAXN = 1e6 + 5;
#define LL long long
struct FenwickTree
{
    int L, R;
    LL sum;
    int val;    ///times for overlap
}tree[MAXN * 4];
map<int,int>mx, my;     ///原始坐标转化成离散化的坐标
map<int,int>idx, idy;   ///离散化的坐标转化成原始坐标
int tempx[MAXN * 4], tempy[MAXN * 4];
int cntx, cnty;         ///离散后x坐标和y坐标总个数,从1开始
void build(int o, int L, int R)
{
    tree[o].L = L, tree[o].R = R, tree[o].val = 0, tree[o].sum = 0;
    if(L == R)  return;
    int mid = (L + R) >> 1;
    if(mid >= L)    build(o * 2, L, mid);
    if(mid < R)     build(o * 2 + 1, mid + 1, R);
}
void push_up(int o)
{
    if(tree[o].val) tree[o].sum = idx[tree[o].R+1] - idx[tree[o].L];    ///注意此处
    else if(tree[o].L == tree[o].R)  tree[o].sum = 0;
    else    tree[o].sum = tree[o * 2].sum + tree[o * 2 + 1].sum;
}
void update(int o, int L, int R, int val)
{
//    system("pause");
    if(tree[o].L >= L && tree[o].R <= R){
        tree[o].val += val;
    }
    else{
        int mid = (tree[o].L + tree[o].R) >> 1;
        if(mid >= L)    update(o * 2, L, R, val);
        if(mid < R)    update(o * 2 + 1, L, R, val);
    }
    push_up(o);
//    if(tree[o].L == tree[o].R){
//        printf("L = %d, idx[tree[o].R] = %d, idx[tree[o].L-1]=%d\n", tree[o].L, idx[tree[o].R], idx[tree[o].L-1]);
//    }
//    printf("o = %d, val = %d, tree[o].L = %d, tree[o].R = %d, tree[o].sum = %I64d\n", o, val, tree[o].L, tree[o].R, tree[o].sum);
}
struct D
{
    int x1, y1, x2, y2;
}d[MAXN];
struct E
{
    int mark;
    int L, R, y;
    int op;
    E(){}
    E(int _L, int _R, int _y, int _op){L = _L, R = _R, y = _y, op = _op;}
}e[MAXN * 4];
bool cmp(D a, D b){return a.y1 < b.y1;}
bool cmp2(E a, E b)
{
    if(a.y == b.y)  return a.op < b.op;
    else    return a.y < b.y;
}
int main()
{
    int n;
    while(scanf("%d", &n) != EOF){
        mx.clear(); my.clear();
        idx.clear(); idy.clear();
        int tempcnt = 0;
        for(int i = 0 ; i < n ; i++){
            scanf("%d%d%d%d", &d[i].x1, &d[i].y1, &d[i].x2, &d[i].y2);
            if(d[i].x1 > d[i].x2)   swap(d[i].x1, d[i].x2);
            if(d[i].y1 > d[i].y2)   swap(d[i].y1, d[i].y2);
            d[i].x2++, d[i].y2++;
//            printf("i = %d, x1 = %d, x2 = %d, y1 = %d, y2 = %d\n", i, d[i].x1, d[i].x2, d[i].y1, d[i].y2);
            tempx[tempcnt] = d[i].x1, tempy[tempcnt++] = d[i].y1;
            tempx[tempcnt] = d[i].x2, tempy[tempcnt++] = d[i].y2;
        }
        sort(tempx, tempx + tempcnt);
        sort(tempy, tempy + tempcnt);
        cntx = cnty = 0;
        for(int i = 0 ; i < tempcnt ; i++){
            if(mx[tempx[i]] == 0)   mx[tempx[i]] = ++cntx, idx[cntx] = tempx[i];
            if(my[tempy[i]] == 0)   my[tempy[i]] = ++cnty, idy[cnty] = tempy[i];
        }
        build(1, 1, cntx);
//        sort(d, d + n, cmp);
        for(int i = 0 ; i < n ; i++){
            e[i * 2] = E(mx[d[i].x1], mx[d[i].x2], my[d[i].y1], 1), e[i * 2].mark = i;
            e[i * 2 + 1] = E(mx[d[i].x1], mx[d[i].x2], my[d[i].y2], -1), e[i * 2 + 1].mark = i;
        }
        LL ans = 0;
        sort(e, e + 2 * n, cmp2);
        for(int i = 0 ; i < 2 * n ; i++){
            update(1, e[i].L, e[i].R - 1, e[i].op);
            if(i < 2 * n - 1)
                ans +=  tree[1].sum * (idy[e[i + 1].y - e[i].y);    ///注意此处顺序
        }
        printf("%I64d\n", ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值