掃描線板子題

Picture

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 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.
題意:
掃描圖形邊界周長。

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
using namespace std;    //掃描線模版題;   只需要理解好原理就能想到,分別對x,y進行掃描;
#define ml root<<1
#define mr root<<1|1
const int N=1e5+55;
int pox[N],poy[N];         //分別記錄x,y,軸離散化後的座標值;
struct nodey{          //存線段;
    int x1,x2,y;
    int val;
}mpy[N];
struct nodex{
    int y1,y2,x;
    int val;
}mpx[N];
struct nod{
    int sum;
    int val;
}rt[N];
bool cmp_y(nodey a, nodey b)   //將y軸按升序排列,對y軸進行掃描;
{
    return a.y<b.y;
}
bool cmp_x(nodex a, nodex b)  //將x軸按升序排列,對x軸進行掃描:
{
    return a.x<b.x;
}
void build_tree()          //初始化樹;
{
    for(int i=0;i<N;++i){
        rt[i].sum=0;
        rt[i].val=0;
    }
}
void up_d(int root, int l, int r, bool k)      //利用線段樹維護每一段的長度;
{
    if(k){                                                  //k爲ture時對y進行掃描,false對x進行掃描;
        if(rt[root].val) rt[root].sum=pox[r+1]-pox[l];      //直接記錄區間長度;
        else if(l==r) rt[root].sum=0;                  //對沒有了的區間進行清零;
        else rt[root].sum=rt[ml].sum+rt[mr].sum;      //上傳數據+清零,維護線段樹;
    }
    else{                                                //同上;
        if(rt[root].val) rt[root].sum=poy[r+1]-poy[l];  
        else if(l==r) rt[root].sum=0;
        else rt[root].sum=rt[ml].sum+rt[mr].sum;
    }
}
void update(int root, int l, int r, int s, int t, int val, bool k)   //線段樹基本操作,遍歷樹;
{
    if(l==s&&r==t){
        rt[root].val+=val;
        up_d(root,l,r,k);
        return ;
    }
    int mid=(l+r)>>1;
    if(mid>=t) update(ml,l,mid,s,t,val,k);
    else if(mid<s) update(mr,mid+1,r,s,t,val,k);
    else update(ml,l,mid,s,mid,val,k),update(mr,mid+1,r,mid+1,t,val,k);
    up_d(root,l,r,k);
}
int main()
{
    int n,i,l,r;
    int x1,x2,y1,y2;
    while(scanf("%d",&n)!=EOF){
        int cnt=1,tx=1,ty=1;
        for(i=1;i<=n;++i){
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);    //錄入數據;
            mpy[cnt]={x1,x2,y1,1};
            mpx[cnt]={y1,y2,x1,1};
            pox[cnt]=x1;
            poy[cnt++]=y1;
            mpy[cnt]={x1,x2,y2,-1};
            mpx[cnt]={y1,y2,x2,-1};
            pox[cnt]=x2;
            poy[cnt++]=y2;
        }
        sort(pox+1,pox+cnt);
        sort(poy+1,poy+cnt);
        for(i=2;i<cnt;++i){                       //離散化處理;
            if(pox[i]!=pox[i-1]) pox[++tx]=pox[i];
            if(poy[i]!=poy[i-1]) poy[++ty]=poy[i];
        }
        sort(mpy+1,mpy+cnt,cmp_y);
        sort(mpx+1,mpx+cnt,cmp_x);
        int temp=0;
        long long ans=0;
        build_tree();
        for(i=1;i<cnt;++i){                          //向上掃描Y軸;
            l=lower_bound(pox+1,pox+tx+1,mpy[i].x1)-pox;
            r=lower_bound(pox+1,pox+tx+1,mpy[i].x2)-pox;
            update(1,1,tx,l,r-1,mpy[i].val,true);
            ans+=abs(rt[1].sum-temp);               //本次的有效線段爲這次掃描的線-上次線的絕對值;
            temp=rt[1].sum;
        }
        build_tree();
        temp=0;
        for(i=1;i<cnt;++i){                       //向右掃描X軸;
        l=lower_bound(poy+1,poy+ty+1,mpx[i].y1)-poy;
        r=lower_bound(poy+1,poy+ty+1,mpx[i].y2)-poy;
        update(1,1,ty,l,r-1,mpx[i].val,false);
        ans+=abs(rt[1].sum-temp);
        temp=rt[1].sum;
        }
        printf("%lld\n",ans);
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章