[HNOI2012]三角形覆盖问题

I.[HNOI2012]三角形覆盖问题

扫描线问题是计算几何里面的一大重点……吗?

不管怎么说,这道题的确要使用扫描线解决。

具体来说,因为\(n\)只有\(10000\),考虑使用\(O(n^2)\)的做法并加以剪枝。

我们首先将所有三角形按照顶点的\(x\)坐标递增顺序。接着,考虑用扫描线维护每一时刻与扫描线相交的所有线段。

明显我们不能维护每一时刻的状况,不然复杂度吃不消;于是,我们只能维护如下几个时刻的状况:

  1. 当一个三角形被加入的时刻;

  2. 当一个三角形结束的时刻;

  3. 当两条原本相交的线段因为坐标的增加而分离的时刻;

同时,对于包含关系的线段,我们只保留外面的线段即可。

在时刻之间的面积,直接采用梯形面积公式即可计算。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m;
struct LINE{
	int x,st,ed;
	LINE(int a=0,int b=0,int c=0){x=a,st=b,ed=c;}
	friend bool operator <(const LINE &x,const LINE &y){
		return x.x<y.x;
	}
}a[10100];
struct Line{
	int st,ed;
	Line(int a=0,int b=0){st=a,ed=b;}
	friend bool operator <(const Line &x,const Line &y){
		return x.st==y.st?x.ed>y.ed:x.st<y.st;
	}
}b[10100];
int Next(){
	int nex=0x3f3f3f3f;
	for(int i=1;i<m;i++)if(b[i].ed>b[i+1].st)nex=min(nex,b[i].ed-b[i+1].st);
	for(int i=1;i<=m;i++)nex=min(nex,b[i].ed-b[i].st);
	return nex;
}
void Decline(int delta){
	for(int i=1;i<=m;i++)b[i].ed-=delta;
	int newm=0;
	for(int i=1;i<=m;i++)if(b[i].ed!=b[i].st)b[++newm]=b[i];
	m=newm;
}
void Reset(){
	sort(b+1,b+m+1);
	int newm=1;
	for(int i=2;i<=m;i++)if(b[i].ed>b[newm].ed)b[++newm]=b[i];
	m=newm;
}
int Calc(){
	int tot=0;
	for(int i=1;i<=m;i++)tot+=b[i].ed-max(b[i].st,b[i-1].ed);
	return tot;
}
ll res;
int main(){
	scanf("%d",&n);
	for(int i=1,x,y,z;i<=n;i++)scanf("%d%d%d",&x,&y,&z),a[i]=LINE(x,y,y+z);
	sort(a+1,a+n+1);
	a[n+1].x=0x3f3f3f3f;
	for(int i=1,nexpos=a[1].x,las=0,laspos=-1;i<=n||nexpos<0x3f3f3f3f;){
		int now=min(nexpos,a[i].x);
		nexpos=now;
		int delta=0;
		if(laspos!=-1)delta=now-laspos;
		laspos=now;
		Decline(delta);
//		printf("PREF:%d\n",now);
//		for(int i=1;i<=m;i++)printf("[%d,%d]",b[i].st,b[i].ed);puts("");
		int NOW=Calc();
		res+=1ll*(NOW+las)*delta;
		if(nexpos!=a[i].x){las=NOW,nexpos+=Next();continue;}
		do{b[++m]=Line(a[i].st,a[i].ed),i++;}while(i<=n&&a[i].x==a[i-1].x);
		Reset();
//		printf("AFTE:%d\n",now);
//		for(int i=1;i<=m;i++)printf("[%d,%d]",b[i].st,b[i].ed);puts("");
		las=Calc();
		nexpos+=Next();
	}
//	printf("%d\n",res);
	printf("%d.%d\n",res>>1,(res&1)?5:0);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14613595.html