HDU 3265(矩形面积并-分割矩形)

Posters

Problem Description
有很多海报,每个海报都被减去了一个矩形(可能全减),现在给出没张海报的位置,求它们的面积并。
保证坐标在(0, 0)到(50000, 50000)之间。没有海报斜着贴,减去的矩形边与x,y轴平行。
 
Input
有很多数据。
对于每组数据第一行有一个整数N (0<N<=50000)表示海报数 接下来n行,每行8个整数 x1, y1, x2, y2, x3, y3, x4, y4, 表示每张海报的左下角坐标(x1, y1),右上角坐标(x2, y2) ,减去的矩形左上角坐标(x3, y3),右上角坐标(x4, y4)(0<=xi, yi<=50000(i=1…4) and x1<=x3<x4<=x2, y1<=y3<y4<=y2).

数据以0结尾。
 


Output
对于每组数据输出一行,表示它们的面积并。
 


Sample Input
2 0 0 10 10 1 1 9 9 2 2 8 8 3 3 7 7 0
 


Sample Output
56
 

这题就是要把矩形差分成如下形式:



然后进行矩形面积并:

谨记问题转化后各数组的大小。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
using namespace std;
#define MAXN (50000+10)
#define MAXT (MAXN*5)
#define MAXXi (50000+10)
#define Lson (x<<1)
#define Rson ((x<<1)^1)
int hpos[MAXN];
int x[MAXN*4]={0};
struct SegMent
{
    int x1,x2,h,type;
    SegMent(){}
    SegMent(int _x1,int _x2,int _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){}
    friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h;}
};
int n,size;
struct SegMent_array
{
    SegMent a[MAXN*8];
    int size;
    SegMent_array():size(0)
    {
        memset(a,0,sizeof(a));
    }

    bool add(int x1,int x2,int y1,int y2)
    {
        if (x1==x2||y1==y2) return 0;
        else
        {
            a[++size]=SegMent(x1,x2,y1,1);
            a[++size]=SegMent(x1,x2,y2,-1);
            return 1;
        }
    }
}a;
struct SegMentTree
{
    long long sum[MAXT],cnt[MAXT],len[MAXT];
    int M,n;
    void fillchar(int _n)
    {
        n=_n;
        M=1;while (M-2<n) M<<=1;
        memset(sum,0,sizeof(sum));
        memset(cnt,0,sizeof(cnt));
        memset(len,0,sizeof(len));
        for (int i=M+1;i<=M+n;i++) len[i]=x[i-M+1]-x[i-M];
        for (int i=M-1;i>=1;i--) len[i]=len[i<<1]+len[(i<<1)^1];
    }
    void pushup(int x)
    {
		sum[x]=(cnt[x])?(len[x]):((x<M)?(sum[Lson]+sum[Rson]):0);
	}
	void update(int x)
	{
		while (x)
		{
			pushup(x);x>>=1;
		}
	}
    void insert(int l,int r,long long c)
	{
		if (l>r) return ;
		l=l-1+M;r=r+1+M;
		int ll=l,rr=r;
		for (;l^r^1;l>>=1,r>>=1)
		{
			if (~l&1) {cnt[l+1]+=c; pushup(l+1);}
			if (r&1) {cnt[r-1]+=c; pushup(r-1);}
		}
//		cout<<endl<<"Push:"<<ll<<' '<<rr<<endl;
		update(ll);update(rr);
	}
	void print()
	{
		for (int i=1;i<=2*M;i++) if (sum[i]) cout<<i<<':'<<sum[i]<<' ';
		cout<<endl;
		for (int i=1;i<=2*M;i++) if (cnt[i]) cout<<i<<':'<<cnt[i]<<' ';
		cout<<endl;
		cout<<endl;
	}
}t;


int main()
{
//  freopen("Hdu3265.in","r",stdin);
    while (scanf("%d",&n)!=EOF)
    {
		if (n==0) break;
	    for (int i=1;i<=n;i++)
    	{
        	int x1,y1,x2,y2,x3,y3,x4,y4;
	        scanf("%d%d%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&x3,&y3,&x4,&y4);
    	    a.add(x1,x3,y1,y4);
        	a.add(x3,x2,y1,y3);
	        a.add(x1,x4,y4,y2);
    	    a.add(x4,x2,y3,y2);
			x[i*4-3]=x1;x[i*4-2]=x2;x[i*4-1]=x3;x[i*4]=x4;
	    }
    	sort(x+1,x+4*n+1);
    	size=unique(x+1,x+4*n+1)-(x+1);
/* 		for (int i=1;i<=size;i++) cout<<x[i]<<' ';
    	cout<<endl;
*/
//		cout<<size;
    	for (int i=1;i<=size;i++) hpos[x[i]]=i;
		t.fillchar(size-1);

		sort(a.a+1,a.a+1+a.size);
//		cout<<'s';
//		for (int i=1;i<=a.size;i++) cout<<a.a[i].x1<<' '<<a.a[i].x2<<' '<<a.a[i].h<<' '<<a.a[i].type<<endl;
		long long ans=0;
		for (int i=1;i<=a.size;i++)
		{
			ans+=t.sum[1]*((long long)a.a[i].h-a.a[i-1].h);
			t.insert(hpos[a.a[i].x1],hpos[a.a[i].x2]-1,a.a[i].type);
/*			cout<<a.a[i].x1<<' '<<a.a[i].x2<<' '<<a.a[i].h<<' '<<a.a[i].type<<endl;
			cout<<ans<<endl;
			t.print();
*/		}
		cout<<ans<<endl;
		a.size=0;
	}
	return 0;
}




POJ 1151(矩形面积并)

Language:
Atlantis
Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 13134   Accepted: 5050

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

Source

Hdu 1542,不过数据变水……


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN (2000+10)
#define MAXT (1000*2*10)
#define Lson (x<<1)
#define Rson ((x<<1)^1)
int tt,n,size;
double x[MAXN];
struct SegMent
{
    double x1,x2,h;
    int type;
    SegMent(){}
    SegMent(double _x1,double _x2,double _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){}
    friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h;    }
}a[MAXN];
map<double , int>  hpos;
double len[MAXT];
struct SegMentTree
{
    int n,M,cnt[MAXT];
    double sum[MAXT];
    int mark[MAXT];
    void fillchar(int _n)
    {
        n=_n;
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(mark,0,sizeof(mark));
        M=1;while (M-2<n) M<<=1;
        x[0]=0;memset(len,0.0,sizeof(len));
        for (int i=M+1;i<=M+size;i++) len[i]=x[i-M]-x[i-M-1];
        for (int i=M-1;i>0;i--) len[i]=len[i<<1]+len[(i<<1)^1];
    }
    void pushup(int x)
    {
        sum[x]=cnt[x]?len[x]:(x>=M?0:sum[Lson]+sum[Rson]);
    }
    void update(int x)
    {
        for (;x;x>>=1)
        {
            pushup(x);
        }
    }

    void insert(int l,int r,int c)
    {
        int ll=l-1+M,rr=r+1+M;
        for (l=l-1+M,r=r+1+M;l^r^1;l>>=1,r>>=1)
        {
            if (~l&1) {cnt[l+1]+=c;pushup(l+1);} /*改变sum的值 */
            if (r&1) {cnt[r-1]+=c;pushup(r-1);}
        }
        update(ll);update(rr);
    }
}t;

int main()
{
//    freopen("Hdu1542.in","r",stdin);
    tt=0;
    while (scanf("%d",&n)!=EOF)
    {
        tt++;
        if (!n) break;
        for (int i=1;i<=2*n;i+=2)
        {
			double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            x[i]=x1;x[i+1]=x2;
            a[i]=SegMent(x1,x2,y1,1);
            a[i+1]=SegMent(x1,x2,y2,-1);
        }

        sort(a+1,a+2*n+1);
        sort(x+1,x+2*n+1);
        size=unique(x+1,x+2*n+1)-(x+1);
        for (int i=1;i<=size;i++) hpos[x[i]]=i;
        t.fillchar(size);


        double ans=0;a[0].h=a[1].h;
        for (int i=1;i<=2*n;i++)
        {
            ans+=(a[i].h-a[i-1].h)*t.sum[1];
            t.insert(hpos[a[i].x1]+1,hpos[a[i].x2],a[i].type);
        }
        printf("Test case #%dnTotal explored area: %.2lfnn",tt,ans);


    }
    return 0;
}

HDU 1542(矩形面积并)

Atlantis

Problem Description
已知Atlantis的地图由许多矩形构成,求它们的面积并。
 


Input
题目有多组数据,每组数据的开头有一个整数n(1<=n<=100),表示地图数,接下来n行,每行4个小数 x1;y1;x2;y2 (0<=x1<x2<=100000;0<=y1<y2<=100000), 表示这张地图左上角坐标 (x1; y1)和右上角坐标 (x2;y2).
数据以0结束
 


Output
对于每组数据,你需要输出一行 “Test case #k”,k表示第k组数据(从1开始).第二行为“Total explored area: a”,a为面积并(保留2位小数),
每组数据后,请输出一个回车。
 


Sample Input
2 10 10 20 20 15 15 25 25.5 0
 


Sample Output
Test case #1 Total explored area: 180.00
 

矩形面积并入门题,

首先把直线拆成上边和下边,按高度排序,

横坐标离散化,建立线段树。

cnt[]表示某条线段被覆盖的次数,sum[]表示一条线段被覆盖的长度

我们在计算cnt[]时,没修改1个cnt[],就用pushup把sum[]更新,得到程序1:



#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN (2000+10)
#define MAXT (1000*2*10)
#define Lson (x<<1)
#define Rson ((x<<1)^1)
int tt,n,size;
double x[MAXN];
struct SegMent
{
    double x1,x2,h;
    int type;
    SegMent(){}
    SegMent(double _x1,double _x2,double _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){}
    friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h;    }
}a[MAXN];
map<double , int>  hpos;
double len[MAXT];
struct SegMentTree
{
    int n,M,cnt[MAXT];
    double sum[MAXT];
    int mark[MAXT];
    void fillchar(int _n)
    {
        n=_n;
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(mark,0,sizeof(mark));
        M=1;while (M-2<n) M<<=1;
        x[0]=0;memset(len,0.0,sizeof(len));
        for (int i=M+1;i<=M+size;i++) len[i]=x[i-M]-x[i-M-1];
        for (int i=M-1;i>0;i--) len[i]=len[i<<1]+len[(i<<1)^1];
    }
    void pushdown(int x)
    {
        if (x>>1) pushdown(x>>1);
        if (mark[x])
        {
            mark[Lson]+=mark[x];
            cnt[Lson]+=mark[x];
            mark[Rson]+=mark[x];
            cnt[Rson]+=mark[x];
            mark[x]=0;
        }
    }
    void pushup(int x)
    {
    //    pushdown(x);cout<<mark[5];
    //    cout<<x<<' ';

        sum[x]=cnt[x]?len[x]:(x>=M?0:sum[Lson]+sum[Rson]);
    }
    void update(int x)
    {
        for (;x;x>>=1)
        {
        //    cout<<"push "<<x<<endl;
            pushup(x);
        }
    }

    void insert(int l,int r,int c)
    {
        int ll=l-1+M,rr=r+1+M;
        for (l=l-1+M,r=r+1+M,pushdown(l>>1),pushdown(r>>1);l^r^1;l>>=1,r>>=1)
        {
            if (~l&1) {cnt[l+1]+=c;update(l+1);/*mark[l+1]+=c;*/} /*改变sum的值 */
            if (r&1) {cnt[r-1]+=c;update(r-1);/* mark[r-1]+=c;*/}
        }
//        update(ll);update(rr); //向上传递
    }
    void print()
    {
        cout<<"cnt ";
        for (int i=1;i<=M*2;i++) if (cnt[i]) cout<<i<<':'<<cnt[i]<<' ';
        cout<<endl;
        cout<<"sum ";
        for (int i=1;i<=M*2;i++) if (sum[i]) cout<<i<<':'<<sum[i]<<' ';
        cout<<endl;
        cout<<"Mark ";
        for (int i=1;i<=M*2;i++) if (mark[i]) cout<<i<<':'<<mark[i]<<' ';
        cout<<endl;
    }
}t;

int main()
{
//    freopen("Hdu1542.in","r",stdin);
    tt=0;
    while (scanf("%d",&n)!=EOF)
    {
        tt++;
        if (!n) break;
        for (int i=1;i<=2*n;i+=2)
        {
            scanf("%lf%lf%lf%lf",&a[i].x1,&a[i].h,&a[i].x2,&a[i+1].h);
            a[i+1].x1=a[i].x1; a[i+1].x2=a[i].x2;
            a[i].type=1;a[i+1].type=-1;
            x[i]=a[i].x1;x[i+1]=a[i].x2;
        }
        sort(a+1,a+2*n+1);
//        for (int i=1;i<=2*n;i++) cout<<a[i].x1<<' '<<a[i].x2<<' '<<a[i].h<<' '<<a[i].type<<endl;

        sort(x+1,x+2*n+1);
        size=unique(x+1,x+2*n+1)-(x+1);
//        for (int i=1;i<=size;i++) cout<<x[i]<<' ';cout<<endl;

        for (int i=1;i<=size;i++) hpos[x[i]]=i;

        t.fillchar(size);
/*        for (int i=1;i<=t.M*2;i++) cout<<len[i]<<' ';
        cout<<endl;
*/        /*
        t.insert(1,3,1);t.print();
        t.insert(2,4,2);
        cout<<t.find(1,3);
        cout<<endl;
        t.print();
        */
    //    t.insert(2,3,1);
        /*
        t.insert(2,3,1);
        t.print();
        t.insert(3,4,1);
        t.print();
        t.insert(2,3,-1);
        t.print();

        */

        double ans=0;a[0].h=a[1].h;
        for (int i=1;i<=2*n;i++)
        {
            ans+=(a[i].h-a[i-1].h)*t.sum[1];
            t.insert(hpos[a[i].x1]+1,hpos[a[i].x2],a[i].type);
/*            t.print();
            cout<<hpos[a[i].x1]+1<<' '<<hpos[a[i].x2]<<endl;
            cout<<t.sum[1]<<endl;
            cout<<ans<<endl;
*/        }
        printf("Test case #%dnTotal explored area: %.2lfnn",tt,ans);


    }
    return 0;
}

上述程序效率较慢(m(logm)^2) ,m为边数


我们考虑到,每次上传实在太耗时了。

仔细观察方程,发现每次修改的点一定是从叶结点到根节点的路上的结点的兄弟(不包括路上)

因此每次被影响的一定是路上的结点。

故我们每次只更新结点的值,最后直接由根节点向上递归,得到程序2-效率为O(mlogm) :


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<cctype>
#include<iostream>
#include<functional>
#include<algorithm>
#include<map>
using namespace std;
#define MAXN (2000+10)
#define MAXT (1000*2*10)
#define Lson (x<<1)
#define Rson ((x<<1)^1)
int tt,n,size;
double x[MAXN];
struct SegMent
{
    double x1,x2,h;
    int type;
    SegMent(){}
    SegMent(double _x1,double _x2,double _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){}
    friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h;    }
}a[MAXN];
map<double , int>  hpos;
double len[MAXT];
struct SegMentTree
{
    int n,M,cnt[MAXT];
    double sum[MAXT];
    int mark[MAXT];
    void fillchar(int _n)
    {
        n=_n;
        memset(cnt,0,sizeof(cnt));
        memset(sum,0,sizeof(sum));
        memset(mark,0,sizeof(mark));
        M=1;while (M-2<n) M<<=1;
        x[0]=0;memset(len,0.0,sizeof(len));
        for (int i=M+1;i<=M+size;i++) len[i]=x[i-M]-x[i-M-1];
        for (int i=M-1;i>0;i--) len[i]=len[i<<1]+len[(i<<1)^1];
    }
    void pushup(int x)
    {
        sum[x]=cnt[x]?len[x]:(x>=M?0:sum[Lson]+sum[Rson]);
    }
    void update(int x)
    {
        for (;x;x>>=1)
        {
            pushup(x);
        }
    }

    void insert(int l,int r,int c)
    {
        int ll=l-1+M,rr=r+1+M;
        for (l=l-1+M,r=r+1+M;l^r^1;l>>=1,r>>=1)
        {
            if (~l&1) {cnt[l+1]+=c;pushup(l+1);} /*改变sum的值 */
            if (r&1) {cnt[r-1]+=c;pushup(r-1);}
        }
        update(ll);update(rr);
    }
}t;

int main()
{
//    freopen("Hdu1542.in","r",stdin);
    tt=0;
    while (scanf("%d",&n)!=EOF)
    {
        tt++;
        if (!n) break;
        for (int i=1;i<=2*n;i+=2)
        {
			double x1,y1,x2,y2;
            scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
            x[i]=x1;x[i+1]=x2;
            a[i]=SegMent(x1,x2,y1,1);
            a[i+1]=SegMent(x1,x2,y2,-1);
        }

        sort(a+1,a+2*n+1);
        sort(x+1,x+2*n+1);
        size=unique(x+1,x+2*n+1)-(x+1);
        for (int i=1;i<=size;i++) hpos[x[i]]=i;
        t.fillchar(size);


        double ans=0;a[0].h=a[1].h;
        for (int i=1;i<=2*n;i++)
        {
            ans+=(a[i].h-a[i-1].h)*t.sum[1];
            t.insert(hpos[a[i].x1]+1,hpos[a[i].x2],a[i].type);
        }
        printf("Test case #%dnTotal explored area: %.2lfnn",tt,ans);


    }
    return 0;
}