Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长

参考  https://www.cnblogs.com/null00/archive/2012/04/22/2464876.html

#include <stdio.h>
#include <algorithm>
#define LEN 10000
using namespace std;

struct Node
{
    int left;
    int right;
    int count;//被覆盖次数
    //所包含的区间数量,如三条[1,2],[2,3],[4,5]线段被覆盖,则line=2,因为 [1,2],[2,3]是连续的。
    int line;//所包含的区间数量
    int lbd;//左端点是否被覆盖   用来辅助对line的计算
    int rbd;//右端点是否被覆盖
    int m;//测度  ,即覆盖的区间长度,如[2,8]就为6
}node[LEN*4];;
struct ScanLine
{
    int x;
    int y1;
    int y2;
    int flag;
}scan[LEN];;
int y[LEN];
void build(int l, int r, int i)
{
    node[i].left = l;
    node[i].right = r;
    node[i].count = 0;
    node[i].m = 0;
    node[i].line = 0;
    if (r - l > 1)
    {
        int middle = (l + r)/2;
        build(l, middle, 2*i + 1);
        build(middle, r, 2*i + 2);
    }
}
//更新测度m
void update_m(int i)
{
    if (node[i].count > 0)
        node[i].m = y[node[i].right] - y[node[i].left];
    else if (node[i].right - node[i].left == 1)
        node[i].m = 0;
    else
    {
        node[i].m = node[2*i + 1].m + node[2*i + 2].m;
    }
}
//更新line
void update_line(int i)
{
    if (node[i].count > 0)
    {
        node[i].lbd = 1;
        node[i].rbd = 1;
        node[i].line = 1;
    }
    else if (node[i].right - node[i].left == 1)
    {
        node[i].lbd = 0;
        node[i].rbd = 0;
        node[i].line = 0;
    }
    else
    {
        node[i].lbd = node[2*i + 1].lbd;
        node[i].rbd = node[2*i + 2].rbd;
        node[i].line = node[2*i + 1].line + node[2*i + 2].line - node[2*i + 1].rbd*node[2*i + 2].lbd;
    }
}
void insert(int l, int r, int i)
{
    //在这里要取离散化之前的原值进行比较
    if (y[node[i].left] >= l && y[node[i].right] <= r)
        (node[i].count)++;
    else if (node[i].right - node[i].left == 1)
        return;
    else
    {
        int middle = (node[i].left + node[i].right)/2;
        if (r <= y[middle])
            insert(l, r, 2*i + 1);
        else if (l >= y[middle])
            insert(l, r, 2*i + 2);
        else
        {
            insert(l, y[middle], 2*i + 1);
            insert(y[middle], r, 2*i + 2);
        }
    }
    update_m(i);
    update_line(i);
}

void remove(int l, int r, int i)
{
    ////在这里要取离散化之前的原值进行比较
    if (y[node[i].left] >= l && y[node[i].right] <= r)
        (node[i].count)--;
    else if (node[i].right - node[i].left == 1)
        return;
    else
    {
        int middle = (node[i].left + node[i].right)/2;
        if (r <= y[middle])
            remove(l, r, 2*i + 1);
        else if (l >= y[middle])
            remove(l, r, 2*i + 2);
        else
        {
            remove(l, y[middle], 2*i + 1);
            remove(y[middle], r, 2*i + 2);
        }
    }
    update_m(i);
    update_line(i);
}

bool cmp(ScanLine line1,ScanLine line2)
{
    if (line1.x == line2.x)
        return line1.flag > line2.flag;
    return (line1.x < line2.x);
}

int main()
{
    int n;
    scanf("%d", &n);
    int x1, y1, x2, y2;
    int i = 0;
    while (n--)
    {
        scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
        scan[i].x = x1;
        scan[i].y1 = y1;
        scan[i].y2 = y2;
        scan[i].flag = 1;
        y[i++] = y1;
        scan[i].x = x2;
        scan[i].y1 = y1;
        scan[i].y2 = y2;
        scan[i].flag = 0;
        y[i++] = y2;
    }
    sort(y, y + i);
    sort(scan, scan + i, cmp);
    //y数组中不重复的个数
    int unique_count = unique(y, y + i) - y;
    //离散化,建立线段树
    build(0, unique_count - 1, 0);
    int perimeter = 0;
    int now_m = 0;
    int now_line = 0;
    for (int j = 0; j < i; j++)
    {
        if (scan[j].flag)
            insert(scan[j].y1, scan[j].y2, 0);
        else
            remove(scan[j].y1, scan[j].y2, 0);
        if (j >= 1)
            perimeter += 2*now_line*(scan[j].x - scan[j-1].x);
        //要减去,因为一个边只能算一次,要减去上一次已经算过的边
        perimeter += abs(node[0].m - now_m);
        now_m = node[0].m;
        now_line = node[0].line;
    }
    printf("%d\n", perimeter);
    return 0;
}

原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12296636.html

时间: 2024-08-28 09:50:47

Picture POJ - 1177 线段树+离散化+扫描线 求交叉图像周长的相关文章

POJ 1177/HDU 1828 picture 线段树+离散化+扫描线 轮廓周长计算

求n个图矩形放下来,有的重合有些重合一部分有些没重合,求最后总的不规则图型的轮廓长度. 我的做法是对x进行一遍扫描线,再对y做一遍同样的扫描线,相加即可.因为最后的轮廓必定是由不重合的线段长度组成的,这样理论上是对的 要注意处理高度相同的线段,把底边优先处理(在代码里就是f标记为1的线段),因为若是一个矩形的底边和另一个矩形的上边重合,则这个轮廓肯定不能算 不过POJ和HDU的数据好像都比较弱,我没进行上面的细节处理也AC了,不过一个很简单的数据就会不对,所以还是要处理一下才是真正正确的代码 我

hdu1828 Picture(线段树+离散化+扫描线)两种方法

C - Picture Time Limit:2000MS     Memory Limit:10000KB     64bit IO Format:%I64d & %I64u Submit Status Description A number of rectangular posters, photographs and other pictures of the same shape are pasted on a wall. Their sides are all vertical or

POJ 2482 Stars in Your Window 线段树+离散化+扫描线

题面据说很美- 每个星星可以根据在窗口的左下角和右上角两个位置建立两条扫描线,之后就是简单的区间增减和求最大值操作了. 注意要处理在边界上的星星是不算的情况,其实只要把左右边界分别增减一个eps即可. #include <cstdio> #include <cstring> #include <iostream> #include <map> #include <set> #include <vector> #include <

【POJ 2482】 Stars in Your Window(线段树+离散化+扫描线)

[POJ 2482] Stars in Your Window(线段树+离散化+扫描线) Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 11294   Accepted: 3091 Description Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw you? I still remembe

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

hdu1255--覆盖的面积(线段树+离散化+扫描线)

E - 覆盖的面积 Time Limit:5000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description 给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积. Input 输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含

Mayor&#39;s posters POJ - 2528 (线段树 + 离散化)

Mayor's posters Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 86160   Accepted: 24734 Description The citizens of Bytetown, AB, could not stand that the candidates in the mayoral election campaign have been placing their electoral post

POJ 2528 (线段树+离散化) Mayor&#39;s posters

因为将每个单位都作为一个最小单元的话会爆内存的 所以,将海报的每个端点进行排序,将这些端点最为最小的区间. 毕竟是刚刚接触线段树,理解起来还有些吃力,还是那句话,题做多了慢慢就好了. 萌萌的AC代码君贴上. 1 //#define LOCAL 2 #include <iostream> 3 #include <algorithm> 4 #include <cmath> 5 using namespace std; 6 7 int n; 8 struct CPost 9

poj3277--City Horizon(线段树+离散化+扫描线)

City Horizon Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 16206   Accepted: 4414 Description Farmer John has taken his cows on a trip to the city! As the sun sets, the cows gaze at the city horizon and observe the beautiful silhouette