BZOJ 1845: [Cqoi2005] 三角形面积并(扫描线)

题目
类似矩形面积并。把交点拿出来排序扫描线即可。
AC Code:

#include<bits/stdc++.h>
#define maxn 105
#define maxm 50005
#define inf 2e9
#define eps 1e-8
using namespace std;

int n;
struct Point{
	double x,y;
	Point(double x=0,double y=0):x(x),y(y){}
	Point operator -(const Point &B)const{ return Point(x-B.x,y-B.y); }
	Point operator +(const Point &B)const{ return Point(x+B.x,y+B.y); }
	double operator *(const Point &B)const{return x*B.y-y*B.x;}
	Point operator *(const double &B)const{return Point(x*B,y*B); }
	bool operator <(const Point &B)const{ return x<B.x; }
}P[maxm],Q[maxm];
int tot;
int sgn(double a){ return a<-eps?-1:a>eps?1:0; }
Point Ipt(Point a,Point b,Point c,Point d){
	Point u = b - a , v = d - c , w = b - d;
	return b + (a-b) * ((w * v) / (u * v));
}

double solve(double mid){
	double ret = 0;
	int cnt = 0;
	static pair<double,double>p[maxm];
	for(int i=0;i<n;i++){
		double Min = inf , Max = -inf;
		for(int k=1;k<=3;k++)
		{
			Point a = P[3*i+k] , b = P[3*i+k%3+1];
			if((a.x <= mid && b.x>=mid) || (a.x>=mid && b.x<=mid))
			{
				double tmp = Ipt(a,b,Point(mid,0),Point(mid,1)).y;
				Min = min(Min , tmp);
				Max = max(Max , tmp);
			}
		}
		if(Min<Max)
			p[cnt++] = make_pair(Min,Max);
	}
	sort(p,p+cnt);
	double mx=-inf;
	for(int i=0;i<cnt;i++){
		if(p[i].first > mx)
		{
			mx = p[i].second;
			ret += mx - p[i].first;
		}
		else{
			if(p[i].second > mx){
				ret += p[i].second - mx;
				mx = p[i].second;
			}
		}
	}
	return ret;
}

int main(){
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%lf%lf%lf%lf%lf%lf",&P[i*3+1].x,&P[i*3+1].y,&P[i*3+2].x,&P[i*3+2].y,&P[i*3+3].x,&P[i*3+3].y);
		Q[++tot] = P[i*3+1];
		Q[++tot] = P[i*3+2];
		Q[++tot] = P[i*3+3];	
	}
	for(int i=0;i<n;i++)
		for(int j=i+1;j<n;j++)
			for(int k1=1;k1<=3;k1++)
				for(int k2=1;k2<=3;k2++){
					Point a=P[3*i+k1],b=P[3*i+k1%3+1],c=P[3*j+k2],d=P[3*j+k2%3+1];
					if(((a-c)*(d-c))*((b-c)*(d-c)) < 0 && ((c-a)*(b-a))*((d-a)*(b-a))<0)
						Q[++tot] = Ipt(a,b,c,d);
				}
	sort(Q+1,Q+1+tot);
	double ans = 0;
	for(int i=2;i<=tot;i++)
		if(sgn(Q[i].x-Q[i-1].x)){
			ans += solve((Q[i].x+Q[i-1].x)*0.5) * (Q[i].x-Q[i-1].x);
		}
	printf("%.2lf\n",ans-eps);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值