zoukankan      html  css  js  c++  java
  • 线段树扫描线求矩形面积交

    Atlantis

    Problem Description

    There are several ancient Greek texts that contain descriptions of the fabled island Atlantis. Some of these texts even include maps of parts of the island. But unfortunately, these maps describe different regions of Atlantis. Your friend Bill has to know the total area for which maps exist. You (unwisely) volunteered to write a program that calculates this quantity.

    Input

    The input file consists of several test cases. Each test case starts with a line containing a single integer n (1<=n<=100) of available maps. The n following lines describe one map each. Each of these lines contains four numbers x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), not necessarily integers. The values (x1; y1) and (x2;y2) are the coordinates of the top-left resp. bottom-right corner of the mapped area.

    The input file is terminated by a line containing a single 0. Don’t process it.

    Output

    For each test case, your program should output one section. The first line of each section must be “Test case #k”, where k is the number of the test case (starting with 1). The second one must be “Total explored area: a”, where a is the total explored area (i.e. the area of the union of all rectangles in this test case), printed exact to two digits to the right of the decimal point.

    Output a blank line after each test case.

    Sample Input
    2
    10 10 20 20
    15 15 25 25.5
    0
    
    Sample Output
    Test case #1
    Total explored area: 180.00 
    

    将x离散化之后,用线段树保存[0,xtot-1]之间有效线段的长度,注意,区间[a,a]代表的是x[a]和x[a+1]之间的距离,类似于差分数组,所以,[l,r]=x[r+1]-x[l];线段最大长度是不同x坐标的个数-1.

    #include<bits/stdc++.h>
    using namespace std;
    #define Init(arr,val) memset(arr,val,sizeof(arr))
    const int inf=0x3f3f3f3f,mod=1e9+7,MAXN=204;
    typedef long long ll;
    #define lson (i<<1)
    #define rson (i<<1|1)
    double xmap[MAXN];//int用惯了,debug了一下午,才发现要double。。。。
    int n,tot,xtot;
    struct Line {
        double x,y,h;
        int flag;
        Line(){}
        Line(double xx,double yy,double hh,double ff):x(xx),y(yy),h(hh),flag(ff){}
        bool operator<(const Line&o)const {return h<o.h;}
    } line[MAXN];
    int add[MAXN<<2];//如果add=k, 说明该区间被k次,但只需计算一次。
    double len[MAXN<<2];
    void pushup(int i,int l,int r) {
        if(add[i])len[i]=xmap[r+1]-xmap[l];//被覆盖,计算一次即可。
        else if(l==r)len[i]=0;//如果没有覆盖而且是叶子,直接=0
        else len[i]=len[lson]+len[rson];//该区间没有覆盖,可能子区间覆盖了
    }
    void update(int f,int x,int y,int i=1,int l=0,int r=xtot-1) {
        if(x<=l&&r<=y) {
            add[i]+=f;
            pushup(i,l,r);
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)update(f,x,y,lson,l,mid);
        if(y>mid)update(f,x,y,rson,mid+1,r);
        pushup(i,l,r);
    }
    int main() {
        int cas=1;
        while(cin>>n,n) {
            tot=0;
            double x1,x2,y1,y2;
            for(int i=0; i<n; i++) {
                cin>>x1>>y1>>x2>>y2;
                xmap[tot]=x1;
                line[tot++]=Line(x1,x2,y1,1);
                xmap[tot]=x2;
                line[tot++]=Line(x1,x2,y2,-1);
            }
            sort(xmap,xmap+tot);
            sort(line,line+tot);
            xtot=1;
            for(int i=1; i<tot; ++i)//去重,离散化。
                if(xmap[i]!=xmap[i-1])
                    xmap[xtot++]=xmap[i];
            Init(add,0);
            Init(len,0);
            double ans=0;
            for(int i=0; i<tot-1; ++i) {
                int x=lower_bound(xmap,xmap+xtot,line[i].x)-xmap;
                int y=lower_bound(xmap,xmap+xtot,line[i].y)-xmap-1;
    			update(line[i].flag,x,y);
                ans+=(line[i+1].h-line[i].h)*len[1];
            }
            printf("Test case #%d
    Total explored area: %.2lf
    
    ",cas++,ans);
        }
        return 0;
    }
    

    覆盖的面积

    Problem Description

    给定平面上若干矩形,求出被这些矩形覆盖过至少两次的区域的面积.
    在这里插入图片描述

    Input

    输入数据的第一行是一个正整数T(1<=T<=100),代表测试数据的数量.每个测试数据的第一行是一个正整数N(1<=N<=1000),代表矩形的数量,然后是N行数据,每一行包含四个浮点数,代表平面上的一个矩形的左上角坐标和右下角坐标,矩形的上下边和X轴平行,左右边和Y轴平行.坐标的范围从0到100000.

    注意:本题的输入数据较多,推荐使用scanf读入数据.

    Output

    对于每组测试数据,请计算出被这些矩形覆盖过至少两次的区域的面积.结果保留两位小数.

    Sample Input
    2
    5
    1 1 4 2
    1 3 3 7
    2 1.5 5 4.5
    3.5 1.25 7.5 4
    6 3 10 7
    3
    0 0 1 1
    1 0 2 1
    2 0 3 1
    
    Sample Output
    7.63
    0.00
    

    求覆盖了两次的面积,覆盖两次的面积由覆盖一次的面积转化而来,1. 区间覆盖多次,2. 区间覆盖一次且子区间覆盖大于一次。

    #include<bits/stdc++.h>
    using namespace std;
    #define Init(arr,val) memset(arr,val,sizeof(arr))
    const int inf=0x3f3f3f3f,mod=1e9+7,MAXN=2004;
    typedef long long ll;
    #define lson (i<<1)
    #define rson (i<<1|1)
    int n,tot,xtot;
    double xmap[MAXN];
    struct Line{
        double l,r,h;
        int flag;
        Line(){}
        Line(double ll,double rr,double hh,int f):l(ll),r(rr),h(hh),flag(f){}
        bool operator<(const Line&o){return h<o.h;}
    }line[MAXN];
    double len[MAXN<<2],len2[MAXN<<2];
    int add[MAXN<<2];
    inline void pushup(int i,int l,int r){
        if(add[i])len[i]=xmap[r+1]-xmap[l];
        else if(l==r)len[i]=0;
        else len[i]=len[lson]+len[rson];
    
        if(add[i]>1)len2[i]=xmap[r+1]-xmap[l];//该区间覆盖多次。
        else if(l==r)len2[i]=0;//区间覆盖少于两次且没有子区间
        else if(add[i]==1)len2[i]=len[lson]+len[rson];//区间覆盖1次,如果子区间有覆盖,则计算进去,若没有,则=0;
        else len2[i]=len2[lson]+len2[rson];//该区间没有覆盖,但子区间可能覆盖多次。
    }
    void update(int f,int x,int y,int i=1,int l=0,int r=xtot-1){
        if(x<=l&&r<=y){
            add[i]+=f;
            pushup(i,l,r);
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)update(f,x,y,lson,l,mid);
        if(y>mid)update(f,x,y,rson,mid+1,r);
        pushup(i,l,r);
    }
    int main(){
        freopen("in.txt","r",stdin);
        int t;
        scanf("%d",&t);
        while(t--){
            int n;
            scanf("%d",&n);
            double x1,y1,x2,y2;
            tot=0;
            for(int i=0;i<n;++i){
                scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
                xmap[tot]=x1;
                line[tot++]=Line(x1,x2,y1,1);
                xmap[tot]=x2;
                line[tot++]=Line(x1,x2,y2,-1);
            }
            sort(xmap,xmap+tot);
            xtot=1;
            for(int i=1;i<tot;++i)
                if(xmap[i]!=xmap[i-1])xmap[xtot++]=xmap[i];
            sort(line,line+tot);
            Init(add,0);
            Init(len,0);
            Init(len2,0);
            double ans=0;
            for(int i=0;i<tot-1;++i){
                int x=lower_bound(xmap,xmap+xtot,line[i].l)-xmap;
                int y=lower_bound(xmap,xmap+xtot,line[i].r)-xmap-1;
                update(line[i].flag,x,y);
                ans+=len2[1]*(line[i+1].h-line[i].h);
            }
            printf("%.2lf
    ",ans);
        }
        return 0;
    }
    

    ACM-ICPC 2017 Asia HongKong .B.

    Considerasquaremapwith N×N cells. We indicate the coordinate of a cell by(i,j),where 1≤i,j≤N. Each cell has a color either white or black. The color of each cell is initialized to white. The map supports the operation flip(([x_{low}, x_{high}], [y_{low}, y_{high]})), which flips the color of each cell in the rectangle ([x_{low}, x_{high}] imes [y_{low}, y_{high}]). Given a sequence of flip operations, our problem is to count the number of black cells in the final map. We illustrate this in the following example. Figure (a)(a) shows the initial map. Next, we call flip([2,4],[1,3]) and obtain Figure (b). Then, we call f lip([1, 5], [3, 5]) and obtain Figure (c). This map contains 18 black cells.
    在这里插入图片描述

    Input

    The first line contains the number of test cases T (T < 10). Each test case begins with a line containing two integers N and K (1 < N,K < 10000), where NN is the parameter of the map size and K is the number of flip operations. Each subsequent line corresponds to a flip operation, with four integers: (x_{low}x_{high}) .

    Output

    For each test case, output the answer in aa line.

    样例输入
    1
    5 2
    2 4 1 3
    1 5 3 5
    
    样例输出
    18
    

    就是特地为这题学的,这题的不同之处在于这题不计算面积覆盖次数为偶数次的矩形,很容易就能想到异或运算,初始为0,覆盖一次为0^1=1,覆盖两次为1 ^1=0.
    还有就是某区间这次操作完后是1,但子区间有过覆盖。
    此题是格子,不是坐标,要转化成坐标。

    #include<bits/stdc++.h>
    using namespace std;
    #define Init(arr,val) memset(arr,val,sizeof(arr))
    const int inf=0x3f3f3f3f,mod=1e9+7,MAXN=20004;
    typedef long long ll;
    #define lson (i<<1)
    #define rson (i<<1|1)
    int n,tot,xtot;
    int xmap[MAXN];
    struct Line{
        int l,r,h;
        Line(){}
    	Line(int ll,int rr,int hh):l(ll),r(rr),h(hh){}
        bool operator<(const Line&o){return h<o.h;}
    }line[MAXN];
    int len[MAXN<<2];
    int add[MAXN<<2];
    inline void pushup(int i,int l,int r){
        if(add[i]&&l==r)len[i]=xmap[r+1]-xmap[l];//没有子区间,直接赋值。
        else if(add[i])len[i]=xmap[r+1]-xmap[l]-len[lson]-len[rson];//有子区间且覆盖,整个区间长度减去子区间覆盖的长度。
        else if(l==r)len[i]=0;
        else len[i]=len[lson]+len[rson];
    }
    void update(int x,int y,int i=1,int l=0,int r=xtot-1){
        if(x<=l&&r<=y){
            add[i]^=1;
            pushup(i,l,r);
            return;
        }
        int mid=(l+r)>>1;
        if(x<=mid)update(x,y,lson,l,mid);
        if(y>mid)update(x,y,rson,mid+1,r);
        pushup(i,l,r);
    }
    int main(){
    //    freopen("in.txt","r",stdin);
        int t;
        scanf("%d",&t);
        while(t--){
            int n,k;
            scanf("%d%d",&n,&k);
            int x1,x2,y1,y2;
            tot=0;
            for(int i=0;i<k;++i){
                scanf("%d%d%d%d",&x1,&x2,&y1,&y2);
                xmap[tot]=x1;
                line[tot++]=Line(x1,x2+1,y1);
                xmap[tot]=x2+1;
                line[tot++]=Line(x1,x2+1,y2+1);
            }
            sort(xmap,xmap+tot);
            xtot=1;
            for(int i=1;i<tot;++i)
                if(xmap[i]!=xmap[i-1])xmap[xtot++]=xmap[i];
            sort(line,line+tot);
            Init(add,0);
            Init(len,0);
            int ans=0;
            for(int i=0;i<tot-1;++i){
                int x=lower_bound(xmap,xmap+xtot,line[i].l)-xmap;
                int y=lower_bound(xmap,xmap+xtot,line[i].r)-xmap-1;
                update(x,y);
                ans+=len[1]*(line[i+1].h-line[i].h);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    

    还有一题
    未完待续...

  • 相关阅读:
    牛客 动物园 (KMP)
    网络流模板与经典模型
    Codeforces Round #698 (Div. 2)
    CF1485X Codeforces Round #701
    CF1479B Painting the Array(贪心+DP)
    「AGC021E」Ball Eat Chameleons
    「AGC034E」 Complete Compress
    「AGC034D」 Manhattan Max Matching
    「ARC103D」 Distance Sums
    「AGC035C」 Skolem XOR Tree
  • 原文地址:https://www.cnblogs.com/foursmonth/p/11315849.html
Copyright © 2011-2022 走看看