I.[HNOI2012]三角形覆盖问题
扫描线问题是计算几何里面的一大重点……吗?
不管怎么说,这道题的确要使用扫描线解决。
具体来说,因为\(n\)只有\(10000\),考虑使用\(O(n^2)\)的做法并加以剪枝。
我们首先将所有三角形按照顶点的\(x\)坐标递增顺序。接着,考虑用扫描线维护每一时刻与扫描线相交的所有线段。
明显我们不能维护每一时刻的状况,不然复杂度吃不消;于是,我们只能维护如下几个时刻的状况:
-
当一个三角形被加入的时刻;
-
当一个三角形结束的时刻;
-
当两条原本相交的线段因为坐标的增加而分离的时刻;
同时,对于包含关系的线段,我们只保留外面的线段即可。
在时刻之间的面积,直接采用梯形面积公式即可计算。
代码:
#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;
}