zoukankan      html  css  js  c++  java
  • 【49.23%】【hdu 1828】Picture

    Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 4487 Accepted Submission(s): 2209

    Problem 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 horizontal. Each rectangle can be partially or totally covered by the others. The length of the boundary of the union of all rectangles is called the perimeter.

    Write a program to calculate the perimeter. An example with 7 rectangles is shown in Figure 1.

    The corresponding boundary is the whole set of line segments drawn in Figure 2.

    The vertices of all rectangles have integer coordinates.

    Input
    Your program is to read from standard input. The first line contains the number of rectangles pasted on the wall. In each of the subsequent lines, one can find the integer coordinates of the lower left vertex and the upper right vertex of each rectangle. The values of those coordinates are given as ordered pairs consisting of an x-coordinate followed by a y-coordinate.

    0 <= number of rectangles < 5000
    All coordinates are in the range [-10000,10000] and any existing rectangle has a positive area.

    Please process to the end of file.

    Output
    Your program is to write to standard output. The output must contain a single line with a non-negative integer which corresponds to the perimeter for the input rectangles.

    Sample Input
    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

    Sample Output
    228

    【题目链接】:http://acm.hdu.edu.cn/showproblem.php?pid=1828

    【题解】

    线段树扫描线求矩形的并周长;
    cnt域仍旧是记录这个区间内下边的长度比上边多的个数;
    sumhx表示这个区间横线的长度;
    sumsx表示这个区间内竖线的个数(去掉在内部的线,只保留不重复的);
    lsx和rsx表示这个区间内的最左边和最右边是否有竖线(用于去掉内部的线);
    从下往上扫描所有的下边和上边;(把所有的边处理处理按照高度排序;)
    用竖线的个数乘两条线的高度差+横线的长度;
    其中横线的长度要用当前整个区间的横线长度减去上一次整个区间的横线长度的绝对值值差来搞;

    /*以下内容看完代码再看:
        那个区间去掉重复的竖直线的;
        可以用
        1-3和3-5来体会;(横坐标)
        即1-3和3-5是两个连在一起的的矩形;
        但是竖线只算1和5,则中间那个3会被删掉->即-=2;(因为会插入两次所以得减2);
    
        然后是那个排序的时候,相同高度的不能直接跳过;还要安装它们的上下边的属性来排;下边要先处理;
        比如下图情况
    */

    这里写图片描述

    //上图如果先处理下边;那个△x会被多算一次;即直接增加了x(因为这个时候上边还没被处理;减last的时候会直接加上x而不是x-△x;


    【完整代码】

    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <set>
    #include <map>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    #include <vector>
    #include <stack>
    #include <string>
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define LL long long
    
    using namespace std;
    
    const int MAXN = 22000;
    const int dx[5] = {0,1,-1,0,0};
    const int dy[5] = {0,0,0,-1,1};
    const double pi = acos(-1.0);
    struct abc
    {
        int l,r,h,k;
    };
    
    int n,num = 0,cnt[MAXN<<2],sumhx[MAXN<<2],sumsx[MAXN<<2];
    bool lsx[MAXN<<2],rsx[MAXN<<2];
    abc a[MAXN];
    
    bool cmp(abc a,abc b)
    {
        if (a.h==b.h)
            return a.k>b.k;
        return a.h < b.h;
    }
    
    void push_up(int rt,int l,int r)
    {
        if (cnt[rt])
        {
            lsx[rt]=rsx[rt] = 1;
            sumhx[rt] = r-l+1;
            sumsx[rt] = 2;
        }
        else
        if (l==r)
            lsx[rt]=rsx[rt]=sumhx[rt]=sumsx[rt] = 0;
        else
        {
            sumhx[rt] = sumhx[rt<<1]+sumhx[rt<<1|1];
            sumsx[rt] = sumsx[rt<<1]+sumsx[rt<<1|1];
            lsx[rt] = lsx[rt<<1];
            rsx[rt] = rsx[rt<<1|1];
            if (rsx[rt<<1] && lsx[rt<<1|1])
                sumsx[rt]-=2;
        }
    }
    
    void up_data(int L,int R,int c,int l,int r,int rt)
    {
        if (L<=l && r<=R)
        {
            cnt[rt]+=c;
            push_up(rt,l,r);
            return;
        }
        int m = (l+r)>>1;
        if (L<=m)
            up_data(L,R,c,lson);
        if (m < R)
            up_data(L,R,c,rson);
        push_up(rt,l,r);
    }
    
    int main()
    {
        //freopen("F:\rush.txt","r",stdin);
        while (~scanf("%d",&n))
        {
            memset(lsx,0,sizeof(lsx));
            memset(rsx,0,sizeof(rsx));
            memset(sumsx,0,sizeof(sumsx));
            memset(sumhx,0,sizeof(sumhx));
            memset(cnt,0,sizeof(cnt));
            num = 0;
            int tl = 10000,tr=-10000;
            for (int i = 1;i <= n;i++)
            {
                int x1,y1,x2,y2;
                scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
                a[++num].l = x1;a[num].r = x2;a[num].h = y1;a[num].k = 1;
                a[++num].l = x1;a[num].r = x2;a[num].h = y2;a[num].k = -1;
                tl = min(tl,x1);tr = max(tr,x2);
            }
            sort(a+1,a+1+num,cmp);
            int last = 0,ans = 0;
            for (int i = 1;i <= num;i++)
            {
                if (a[i].l<a[i].r)
                    up_data(a[i].l,a[i].r-1,a[i].k,tl,tr-1,1);
                ans += sumsx[1]*(a[i+1].h-a[i].h);
                ans += abs(sumhx[1]-last);
                last = sumhx[1];
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    
  • 相关阅读:
    造数据
    自定义注解
    利用线程池,同步线程实现并发
    ThreadPoolExecutor 线程池
    velocity 模板
    [python] 解析xml文件
    url 中需要转义的字符
    Appium 坑
    TestNG 101
    【python】print · sys.stdout · sys.stderr
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632088.html
Copyright © 2011-2022 走看看