zoukankan      html  css  js  c++  java
  • [洛谷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;
    }
    
  • 相关阅读:
    第一篇博客
    【面试大系】PHP程序员的知识盘点
    【PHP资源】PHP 资源大全
    【前端经纬】将页面元素定位
    大爱卡农三百年
    【夯实PHP基础】PHP标准库 SPL
    【http抓包】记录一次抓手机app的接口
    【算法】PHP实现冒泡排序和快速排序--防遗忘
    Apache的初中级面试题
    【生活感悟系列】感悟在一瞬间(不断完善中)
  • 原文地址:https://www.cnblogs.com/BCOI/p/10423238.html
Copyright © 2011-2022 走看看