codevs3044 矩形面积求并 线段树+扫描线

首先我们离散化,然后按照纵坐标从下往上扫,每扫到一条边,就把这条边的边权压入线段树——规定始边边权为1,终边边权为-1

每次从下往上枚举一条边,将每两个坐标之间的间隔看成是一个点,每次枚举看那个间隔权值>1,统计下来,乘以两条边之间的距离。

当然枚举间隔的时候不必全扫一边,如果一个区间的和为零,直接return

#include <map>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=100+2;
struct LINE{
	int t;
	double sx,tx,y;
	LINE(){}
	LINE(int _t,double _sx,double _tx,double _y):t(_t),sx(_sx),tx(_tx),y(_y){}
}line[2*MAXN];
typedef struct NODE{
	int l,r,s,add;
	NODE *lchild,*rchild;
	NODE(){}
	NODE(int _l,int _r):l(_l),r(_r),s(0),add(0),lchild(0),rchild(0){}
} *TREE;
TREE root;
int N,M,b[2*MAXN];
double x1,x2,y1,y2,ans,width,a[2*MAXN],l[2*MAXN];
map<double,int> table;

bool cmp1(LINE a,LINE b){ return a.y<b.y;}

bool cmp2(int x,int y){ return a[x]<a[y];}

void Pushup(TREE &x){ x->s=x->lchild->s+x->rchild->s;}

void Pushdown(TREE &x,int m){
    if(x->add){
        x->lchild->s+=x->add*(m-(m>>1));
        x->rchild->s+=x->add*(m>>1);
        x->lchild->add+=x->add,x->rchild->add+=x->add,x->add=0;
    }
}

void Build(TREE &x,int l,int r){
	x=new NODE(l,r);
	if(l==r) return;

	int m=(l+r)>>1;
	Build(x->lchild,l,m),Build(x->rchild,m+1,r);
}

void Update(TREE &x,int l,int r,int v){
    if(x->l>=l && x->r<=r){
        x->add+=v,x->s+=v*(x->r-x->l+1);
        return;
    }

    Pushdown(x,x->r-x->l+1);

    int m=(x->l+x->r)>>1;
    if(l<=m) Update(x->lchild,l,r,v);
    if(r>m) Update(x->rchild,l,r,v);

    Pushup(x);
}

bool Query(TREE &x,int p){
    if(x->l==x->r) return x->s;

    Pushdown(x,x->r-x->l+1);

    if(!x->s) return 0;

    int m=(x->l+x->r)>>1;
    if(p<=m) return Query(x->lchild,p);
    return Query(x->rchild,p);
}

void Erase(TREE &x){
    if(!x) return;
    Erase(x->lchild),Erase(x->rchild);
    delete x;
}

int main(){
	while(scanf("%d",&N)!=EOF){
		if(!N) break;

		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		memset(l,0,sizeof(l));
		memset(line,0,sizeof(line));
		table.clear(),M=0;

		for(int i=1;i<=N;i++){
			cin >> x1 >> y1 >> x2 >> y2;
			line[++M]=LINE(1,x1,x2,y1),a[M]=x1,b[M]=M;
			line[++M]=LINE(-1,x1,x2,y2),a[M]=x2,b[M]=M;
		}
		sort(line+1,line+M+1,cmp1);
		sort(b+1,b+M+1,cmp2);

		N=0;
		for(int i=1,t=0;i<=M;i++)
			if(!t || a[b[i]]!=a[b[t]])
				table[a[b[i]]]=++N,l[N]=a[b[i]]-a[b[t]],t=i;

		Build(root,1,N),ans=width=0;
		for(int i=1;i<=M;i++){
			ans+=(line[i].y-line[i-1].y)*width;

            if(table[line[i].sx]+1<=table[line[i].tx])
                Update(root,table[line[i].sx]+1,table[line[i].tx],line[i].t);

			width=0;
			for(int j=2;j<=N;j++)
				if(Query(root,j)) width+=l[j];
		}
		printf("%.2lf\n",ans);

		Erase(root);
	}

	return 0;
}


你可能感兴趣的:(codevs3044 矩形面积求并 线段树+扫描线)