[USACO5.5]矩形周长Picture[扫描线+线段树]

题意:给出一些矩阵,求这些矩阵合并后外部(被包括在内部的不算)周长

端点-1这个是用点代替了边,区间内有几个点就代表区间长度是多少

#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
inline void chmax(int &x, int y) {if (x < y) x = y;}
inline void chmin(int &x, int y) {if (x > y) x = y;}
int Max = -inf, Min = inf, n, m, tot, ans, lastlen, x, y, xx, yy;
struct Edge {
    int l, r, h, v;
    inline bool operator < (const Edge & rhs) const {
        return h == rhs.h ? v > rhs.v : h < rhs.h;
    }
} G[10005];
inline void add(int l, int r, int h, int v) {
    G[++tot] = (Edge) {l, r, h, v};
}
struct Node {
    int sum, cnt, len;
    //sum区间整体覆盖次数,cnt有几条不相交的线段覆盖了这个区间
    //len区间内被覆盖的长度
    bool rcvd, lcvd;//左右端点是否被覆盖
    Node *ls, *rs;
    inline void pushup(int l, int r) {
        if (sum) cnt = 1, len = r-l+1, lcvd = rcvd = 1;
        else if (l == r) len = 0, cnt = 0, lcvd = rcvd = 0;//Attention
        else {
            len = ls->len + rs->len;
            cnt = ls->cnt + rs->cnt;
            if (ls->rcvd && rs->lcvd) --cnt;
            lcvd = ls->lcvd;
            rcvd = rs->rcvd;
        }
    }
} pool[100005], *root;
void add(Node *cur, int l, int r, int ql, int qr, int v) {
    if (ql <= l && r <= qr) return cur->sum += v, cur->pushup(l, r);
    int mid = l+r>>1;
    if (ql <= mid) add(cur->ls, l, mid, ql, qr, v);
    if (qr >  mid) add(cur->rs, mid+1, r, ql, qr, v);
    cur->pushup(l, r);
}
inline Node *newNode() {
    static int cnt = 0;
    return &(pool[cnt++]);
}
Node *build(int l, int r) {
    Node *cur = newNode();
    if (l == r) return cur;
    int mid = l+r>>1;
    cur->ls = build(l, mid), cur->rs = build(mid+1, r);
    return cur;
}

int main(void) {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        scanf("%d%d%d%d", &x, &y, &xx, &yy);
        chmax(Max, xx), chmin(Min, x), add(x, xx, y, 1), add(x, xx, yy, -1);
    }
    if (Min <= 0) {//把坐标转为正数,其实直接加上10001(本题坐标最大值)也是可以的
        for(int i = 1; i <= tot; ++i) G[i].l += -Min+1, G[i].r += -Min+1;
        Max -= Min;
    }
    root = build(1, Max);
    sort(G+1, G+1+tot);
    for(int i = 1; i <= tot; ++i) {
        add(root, 1, Max, G[i].l, G[i].r-1, G[i].v);//不是很懂为什么要-1,这奇怪的方式
        while(G[i].h==G[i+1].h&&G[i].v==G[i+1].v) {//防止多次统计答案
            ++i;
            add(root, 1, Max, G[i].l, G[i].r-1, G[i].v);
        }
        ans += abs(root->len-lastlen);//统计横边长度
        lastlen = root->len;
        ans += root->cnt*2*(G[i+1].h-G[i].h);//统计竖边长度
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/storz/p/10191558.html

时间: 2024-10-11 22:37:02

[USACO5.5]矩形周长Picture[扫描线+线段树]的相关文章

USACO5.5 矩形周长 Picture | 扫描线 + 线段树

题目:Luogu 1856 扫描线,将矩形拆成两条边分别为 +1 和 -1,计算无重叠部分的长度. 由于 update 区间 [a, b] 和 [b, c] 时会把 b 加两次,所以统一转换成 [a,b),累加长度的时候再将右端点右移. 需要注意,在覆盖一条边时,不能直接累加边的长度,像下图: 在覆盖边 [1,4] 前,[3,4] 已经累加过了,所以此时应该累计的是 [1,4] 的长度减去已经覆盖过的长度,然后再把 [1,4] 覆盖上: 相应的,在删除 [1,4] 这条边时,累计的是删除 [1,

luogu P1856 [USACO5.5]矩形周长Picture 扫描线 + 线段树

Code: #include<bits/stdc++.h> #define maxn 200007 #define inf 100005 using namespace std; void setIO(string s) { string in=s+".in"; freopen(in.c_str(),"r",stdin); } struct Edge { int l,r,h,flag; }edges[maxn]; int n; namespace tr

[线段树扫描线][USACO5.5]矩形周长Picture

墙上贴着许多形状相同的海报.照片.它们的边都是水平和垂直的.每个矩形图片可能部分或全部的覆盖了其他图片.所有矩形合并后的边长称为周长. 所有矩形的边界.所有矩形顶点的坐标都是整数. 输入文件的第一行是一个整数N(0<=N<5000),表示有多少个矩形.接下来N行给出了每一个矩形左下角坐标和右上角坐标(所有坐标的数值范围都在-10000到10000之间). 输出文件只有一个正整数,表示所有矩形的周长. 题解 线段树扫描线  https://www.luogu.org/problemnew/sol

hdu1828 (Picture) &amp;poj 1177( Picture)&amp;sdibt 2390(5.5.1 Picture 矩形周长)(线段树+扫描)

题目地址:hdu1828 (Picture)  & poj 1177( Picture) & sdibt 2390(5.5.1 Picture 矩形周长) 题目大意: 给你N个矩形,求出N个矩形构成的周长. 解题思路: 线段数+扫描线. 推荐博客: POJ1177 Picture(线段树求轮廓周长) POJ 1177 Picture (线段树+离散化+扫描线) 详解 注意事项: 该题在求面积的基础上有了升级,多写了一个被调需要求出投影与Y轴有几段,不然样例会少算20,就是给出图形中间的小矩

POJ1151Atlantis 矩形面积并 扫描线 线段树

欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1151 题意概括 给出n个矩形,求他们的面积并. n<=100 题解 数据范围极小. 我们分3种算法逐步优化. 算法1: O(n3) 如果这n个矩形的坐标都是整数,而且比较小,那么我们显然可以用最暴力的方法:一个一个打标记. 但是不是这样的. 坐标大小很大,而且是实数. 然而我们发现差不多,只要先离散化一下,然后再打标记即可. 算法2:O(n2) 实际上,上面的方法十分慢.如果n的范围到了1000,

poj-1177 Picture(矩形周长并,线段树+扫描线)

题目链接:点击打开链接 Picture Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 11706   Accepted: 6175 Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical o

[USACO5.5] 矩形周长Picture

https://www.luogu.org/problemnew/show/P1856 1.每个矩形由两条横向边和两条纵向边组成. 2.对于横向边,按纵坐标排序.设当前讨论的边为 A [s , t] 如果 A 是某个矩形的靠下的边,在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 如果 A 是某个矩形的靠上的边,先删除它的对应边,再在树中查询[s,t]区间中被覆盖的长度为x,那么加上这条边后将增加(t-s-x); 3.对于纵向边,按横坐标排序,讨论方法与横向边相

hdu1542 Atlantis(扫描线+线段树+离散)矩形相交面积

题目链接:点击打开链接 题目描写叙述:给定一些矩形,求这些矩形的总面积.假设有重叠.仅仅算一次 解题思路:扫描线+线段树+离散(代码从上往下扫描) 代码: #include<cstdio> #include <algorithm> #define MAXN 110 #define LL ((rt<<1)+1) #define RR ((rt<<1)+2) using namespace std; int n; struct segment{ double l

POJ训练计划1177_Picture(扫描线/线段树+离散)

解题报告 题意: 求矩形周长和. 思路: 左扫上扫,扫过了. #include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; struct Seg { int lx,rx,ly,ry,h,v; friend bool operator < (Seg a,Seg b) { re