覆盖的面积 HDU - 1255 扫描线/二次覆盖

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=1010;

int n;
double X[maxn<<1];

struct Edge{
	double l,r,h;
	int v;
	Edge(){};
	Edge(double a,double b,double c,int d):l(a),r(b),h(c),v(d){};
	bool operator<(const Edge &b)const{
		if(h==b.h)return v>b.v;
		return h<b.h;
	}
}edge[maxn<<1];

struct node{
	int l,r,cnt;
	double s,ss;
}ST[maxn<<3];

void build(int l,int r,int rt){
	ST[rt].l=l;ST[rt].r=r;
	ST[rt].cnt=ST[rt].s=ST[rt].ss=0;
	if(l==r)return;
	int m=l+r>>1;
	build(l,m,rt<<1);
	build(m+1,r,rt<<1|1);
}

void cal(int l,int r,int rt){
	if(ST[rt].cnt){
		ST[rt].s=X[r+1]-X[l];
	}else if(ST[rt].l==ST[rt].r){
		ST[rt].s=0;
	}else{
		ST[rt].s=ST[rt<<1].s+ST[rt<<1|1].s;
	}
	///
	if(ST[rt].cnt>1){
		ST[rt].ss=X[r+1]-X[l];
	}else if(l==r){
		ST[rt].ss=0;
	}else if(ST[rt].cnt==1){
		ST[rt].ss=ST[rt<<1].s+ST[rt<<1|1].s;
	}else{
		ST[rt].ss=ST[rt<<1].ss+ST[rt<<1|1].ss;
	}
}

void update(int a,int b,int v,int l,int r,int rt){
	if(a<=l&&b>=r){
		ST[rt].cnt+=v;
		cal(l,r,rt);
		return;
	}
	int m=l+r>>1;
	if(a<=m)update(a,b,v,l,m,rt<<1);
	if(b>m)update(a,b,v,m+1,r,rt<<1|1);
	cal(l,r,rt);
}

int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		int tt=0;
		for(int i=1;i<=n;i++){
			double x1,x2,y1,y2;
			scanf("%lf %lf %lf %lf",&x1,&y1,&x2,&y2);
			X[++tt]=x1;
			edge[tt]=Edge(x1,x2,y1,1);
			X[++tt]=x2;
			edge[tt]=Edge(x1,x2,y2,-1);
		}
		sort(X+1,X+tt+1);
		sort(edge+1,edge+tt+1);
		int m=1;
		for(int i=2;i<=tt;i++){
			if(X[i]!=X[i-1])X[++m]=X[i];
		}
		build(1,m,1);

		double ans=0;
		for(int i=1;i<tt;i++){
			int l=lower_bound(X+1,X+m+1,edge[i].l)-X;
			int r=lower_bound(X+1,X+m+1,edge[i].r)-X-1;
			update(l,r,edge[i].v,1,m,1);
			ans+=ST[1].ss*(edge[i+1].h-edge[i].h);

		}
		printf("%.2lf\n",ans);
	}
}

大部分代码风格能和扫描线保持一致还蛮开心的。。

多次覆盖的核心就在于cal函数

若当前区间被覆盖过一次,当前区间被覆盖2次的长度就加上子节点们覆盖1次的长度

当时听学长讲的时候还感觉很迷,当时光听,没分清楚覆盖次数和覆盖长度。。orz

估计判AC的时候给了eps吧。。不然我样例都没过啊(

posted @ 2017-06-04 01:41  Drenight  阅读(147)  评论(0编辑  收藏  举报