[洛谷P1856] [USACO5.5]矩形周长Picture

洛谷题目链接:[USACO5.5]矩形周长Picture

题目背景

墙上贴着许多形状相同的海报、照片。它们的边都是水平和垂直的。每个矩形图片可能部分或全部的覆盖了其他图片。所有矩形合并后的边长称为周长。

题目描述

编写一个程序计算周长。

如图1所示7个矩形。

如图2所示,所有矩形的边界。所有矩形顶点的坐标都是整数。

输入输出格式

输入格式:

输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形。接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间)。

输出格式:

输出文件只有一个正整数,表示所有矩形的周长。

输入输出样例

输入样例#1:

7
-15 0 5 10
-5 8 20 25
15 -4 24 14
0 -6 16 4
2 15 10 22
30 10 36 20
34 0 40 16

输出样例#1:

228

题意: 给出一堆矩形,要你计算周长.

题解: 类似一堆矩形要你求某些信息的,基本上都可以用扫描线来做.

首先还是将矩形拆成线按照坐标排序,然后我们需要在线段树中记录几个变量:\(cov\)表示这个区间被覆盖的长度,\(sum\)表示这个区间的和(我们会在每次加入线段的时候给区间加上一个权值,会直接修改在\(sum\)变量里,但是\(sum\)标记不会下放).

接下来考虑如何写\(push\_up\)函数.首先判断一个节点被覆盖的长度先要看这个节点的\(sum\)是否有值,因为任何加入/删除线段的操作都会对\(sum\)进行修改,那么如果\(sum\)有值,显然\(cov=r-l+1\)(我这里使用的是闭区间).

如果\(sum\)的值为\(0\)呢?这时候我们需要判断这个节点是否为叶子节点,如果是叶子节点则\(cov=0\),否则\(cov=cov_{lson}+cov_{rson}\),判断是否为叶子的原因是防止越界.

然后查询的时候直接返回\(1\)节点的\(cov\)值就是整个区间内的覆盖数了.

那么答案如何统计呢?我这里是将\(x,y\)轴分两次求的,实际上可以一次做完,但是我自己\(yy\)的时候没想到这么多...

其实我们只需要每次插入一条线段,然后加入这次插入后\(cov\)的变化量的绝对值就可以了.

不懂可以看下代码.

#include<bits/stdc++.h>
#define ll(x) (x << 1)
#define rr(x) (x << 1 | 1)
using namespace std;
const int N = 10000+5;

int n, cnt[2], ans = 0;

struct line{ int x, l, r, v; }a[2][N*2];

bool cmp(line a, line b){ return a.x != b.x ? a.x < b.x : a.v > b.v; }

struct SegmentTree{ int l, r, sum, cov; }t[2][N*8];

void up(int x, int k){
    if(t[k][x].sum) t[k][x].cov = t[k][x].r-t[k][x].l+1;
    else if(t[k][x].l == t[k][x].r) t[k][x].cov = 0;
    else t[k][x].cov = t[k][ll(x)].cov+t[k][rr(x)].cov;
}

void build(int x, int l, int r, int k){
    t[k][x].l = l, t[k][x].r = r, t[k][x].sum = t[k][x].cov = 0;
    if(l == r) return; int mid = (l+r>>1);
    build(ll(x), l, mid, k), build(rr(x), mid+1, r, k);
}

void update(int x, int l, int r, int val, int k){
    if(l <= t[k][x].l && t[k][x].r <= r){
        t[k][x].sum += val, up(x, k); return;
    }
    int mid = (t[k][x].l+t[k][x].r>>1);
    if(l <= mid) update(ll(x), l, r, val, k);
    if(mid < r) update(rr(x), l, r, val, k); up(x, k);
}

void solve(int k){
    int last = 0, pos = 1; build(1, 1, N*2, k);
    sort(a[k]+1, a[k]+cnt[k]+1, cmp);
    for(pos = 1; pos <= cnt[k]; pos++){
        update(1, a[k][pos].l, a[k][pos].r-1, a[k][pos].v, k); //
        int add = abs(t[k][1].cov-last);
        ans += abs(t[k][1].cov-last), last = t[k][1].cov;
    }
}

int main(){
    ios::sync_with_stdio(false);
    int a1, b1, a2, b2; cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a1 >> b1 >> a2 >> b2;
        a1 += N, b1 += N, a2 += N, b2 += N;
        a[0][++cnt[0]] = (line){ a1, b1, b2, 1 };
        a[0][++cnt[0]] = (line){ a2, b1, b2, -1 };
        a[1][++cnt[1]] = (line){ b1, a1, a2, 1 };
        a[1][++cnt[1]] = (line){ b2, a1, a2, -1 };
    }
    solve(0), solve(1);
    cout << ans << endl;
    return 0;
}
posted @ 2019-02-24 21:24  Brave_Cattle  阅读(343)  评论(0编辑  收藏  举报