题目描述
传送门
题目大意:给出n个三角形,求它们并的面积。
题解
MD被卡了一下午精度,各种不爽!!!
同样被卡的同学建议使用long double试一试。。。。
我们把三角形的顶点以及所有交点的横坐标离散,那么相邻两列之间的图形要么是梯形要么是三角形,只要统计出两列上的被覆盖区域的长度,就可以用(上底+下底)*高/2来计算。
统计覆盖区域的话,找出所有的区间,左端点排序后扫一遍就可以了。
有一种情况需要注意,就是三角形的一条边平行于y轴,这种情况计算时只能作为上底,或者只能作为下底,特判一下即可。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 300003
#define eps 1e-12
using namespace std;
const long double inf=1e9;
long double pos[N],ans[N],ans1[N],L[N],R[N];
int n,t,cnt,opt[N];
struct data{
long double x,y;
data(long double X=0,long double Y=0){
x=X,y=Y;
}
bool operator ==(const data &a) {
return x==a.x&&y==a.y;
}
}p[N],q[N],h[100];
data operator +(data a,data b){ return data(a.x+b.x,a.y+b.y);}
data operator -(data a,data b){ return data(a.x-b.x,a.y-b.y);}
data operator *(data a,double t){return data(a.x*t,a.y*t);}
data operator /(data a,double t) {return data(a.x/t,a.y/t);}
struct line{
data a[5],b[5];
long double mx,mn;
}tr[303];
int dcmp(long double x)
{
if (fabs(x)<eps) return 0;
return x>0?1:-1;
}
long double cross(data a,data b)
{
return a.x*b.y-a.y*b.x;
}
bool check(data a,data b,data c,data d)
{
long double c1=cross(c-a,b-a); long double c2=cross(d-a,b-a);
long double d1=cross(a-c,d-c); long double d2=cross(b-c,d-c);
return dcmp(c1)*dcmp(c2)<0&&dcmp(d1)*dcmp(d2)<0;
}
data glt(data a,data a1,data b,data b1)
{
data v=a1-a; data w=b1-b;
data u=a-b;
long double t=cross(w,u)/cross(v,w);
return a+v*t;
}
int cmp(data a,data b)
{
return a.x<b.x||a.x==b.x&&a.y<b.y;
}
long double solve()
{
sort(q+1,q+t+1,cmp); long double len=0;
long double l=q[1].x; long double r=q[1].y;
for (int i=2;i<=t+1;i++){
if (q[i].x>r||i==t+1) {
len+=r-l;
l=q[i].x; r=q[i].y;
}
else r=max(r,q[i].y);
}
return len;
}
int check(int i,data a,data b,data c,long double mx,long double mn)
{
int t=0;
if (a.x==mx) t++,L[i]=min(L[i],a.y),R[i]=max(R[i],a.y);
if (b.x==mx) t++,L[i]=min(L[i],b.y),R[i]=max(R[i],b.y);
if (c.x==mx) t++,L[i]=min(L[i],c.y),R[i]=max(R[i],c.y);
if (t>=2) return 1;
t=0; L[i]=inf; R[i]=-inf;
if (a.x==mn) t++,L[i]=min(L[i],a.y),R[i]=max(R[i],a.y);
if (b.x==mn) t++,L[i]=min(L[i],b.y),R[i]=max(R[i],b.y);
if (c.x==mn) t++,L[i]=min(L[i],c.y),R[i]=max(R[i],c.y);
if (t>=2) return 2;
}
int main()
{
freopen("a.in","r",stdin);
// freopen("my.out","w",stdout);
cnt=0; scanf("%d",&n);
for (int i=1;i<=n;i++){
data x,y,z; L[i]=inf; R[i]=-inf;
cin>>x.x>>x.y;
cin>>y.x>>y.y;
cin>>z.x>>z.y;
tr[i].mx=tr[i].mn=x.x; tr[i].mx=max(y.x,tr[i].mx); tr[i].mx=max(z.x,tr[i].mx);
tr[i].mn=min(y.x,tr[i].mn); tr[i].mn=min(z.x,tr[i].mn);
tr[i].a[1]=x; tr[i].b[1]=y;
tr[i].a[2]=y; tr[i].b[2]=z;
tr[i].a[3]=z; tr[i].b[3]=x;
p[++cnt]=x; p[++cnt]=y; p[++cnt]=z;
opt[i]=check(i,x,y,z,tr[i].mx,tr[i].mn);
}
for (int i=1;i<=n;i++)
for (int k=1;k<=3;k++)
for (int j=i+1;j<=n;j++)
for (int l=1;l<=3;l++)
if (check(tr[i].a[k],tr[i].b[k],tr[j].a[l],tr[j].b[l]))
p[++cnt]=glt(tr[i].a[k],tr[i].b[k],tr[j].a[l],tr[j].b[l]);
for (int i=1;i<=cnt;i++) pos[i]=p[i].x;
sort(pos+1,pos+cnt+1);
cnt=unique(pos+1,pos+cnt+1)-pos-1;
for (int i=1;i<=cnt;i++) {
data a=data(pos[i],-inf); data b=data(pos[i],inf); t=0;
for (int j=1;j<=n;j++){
if (pos[i]<tr[j].mn||pos[i]>tr[j].mx) continue;
if (opt[j]==2&&!dcmp(tr[j].mn-pos[i])) continue;
if (opt[j]==1&&!dcmp(tr[j].mx-pos[i])) {
q[++t].x=L[j]; q[t].y=R[j];
continue;
}
int t1=0;
for (int k=1;k<=3;k++) {
data c=tr[j].a[k]; data d=tr[j].b[k];
if (check(a,b,c,d)) h[++t1]=glt(a,b,c,d);
if (!dcmp(c.x-pos[i])) h[++t1]=c;
if (!dcmp(d.x-pos[i])) h[++t1]=d;
}
t1=unique(h+1,h+t1+1)-h-1;
if (t1<2) continue;
q[++t].x=min(h[1].y,h[2].y); q[t].y=max(h[1].y,h[2].y);
}
ans[i]=solve();
t=0;
for (int j=1;j<=n;j++){
if (pos[i]<tr[j].mn||pos[i]>tr[j].mx) continue;
if (opt[j]==1&&!dcmp(tr[j].mx-pos[i])) continue;
if (opt[j]==2&&!dcmp(tr[j].mn-pos[i])) {
q[++t].x=L[j]; q[t].y=R[j];
continue;
}
int t1=0;
for (int k=1;k<=3;k++) {
data c=tr[j].a[k]; data d=tr[j].b[k];
if (check(a,b,c,d)) h[++t1]=glt(a,b,c,d);
if (!dcmp(c.x-pos[i])) h[++t1]=c;
if (!dcmp(d.x-pos[i])) h[++t1]=d;
}
t1=unique(h+1,h+t1+1)-h-1;
if (t1<2) continue;
q[++t].x=min(h[1].y,h[2].y); q[t].y=max(h[1].y,h[2].y);
}
ans1[i]=solve();
}
long double sum=0;
for (int i=2;i<=cnt;i++) sum+=(ans[i]+ans1[i-1])*(pos[i]-pos[i-1])/2.0;
printf("%.2lf\n",(double)sum);
}