luogu P3249 [HNOI2016]矿区

luogu

我 不 会 容 斥

首先一定要解决的问题是把所有多边形区域给找出来.这个可以枚举每个点,然后枚举每条边,每次走到下一个点,然后边改成逆时针方向的下一条边,重复此过程直到回到原点,那么就找到了一个多边形,这里我们再对每个点的每条边记录这条边和逆时针方向的下一条边夹住的多边形编号.多边形面积可以三角剖分算,但是为了防止精度误差,叉积就不用除2了,这样算出来的面积和面积平方和分别是原来的2倍和4倍.并且可以发现这些多边形里有一个面积为负的,也就是最外围的区域

因为这是平面图,所以我们对于任意两个有公共边的多边形连边,就可以得到对偶图.然后抠出对偶图的一棵生成树,再以最外围的区域代表的点为根dfs一遍树,求出每个点的子树里面面积之和和面积平方和.考虑每次询问,肯定是要求出一些子树信息的和,当然子树可能会包含询问区域以外的信息,那么再减掉一些子树信息即可.手玩可以发现如果一条树边上父亲在区域外面而儿子在区域内则加上对应儿子子树信息,如果父亲在区域内面而儿子在区域外则减去对应儿子子树信息,这个画画图应该比较好理解.最后求出来的面积和为原来2倍,面积平方和为原来4倍,所以对于面积和\(*2\)后化为最简分数即可

#include<bits/stdc++.h>
#define LL long long
#define db double

using namespace std;
const int N=1e5+10;
const db eps=1e-10;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9'){if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+(ch^48);ch=getchar();}
    return x*w;
}
db f[N];
struct node
{
	db x,y;
	bool operator < (const node &bb) const {return x<bb.x;}
	node operator - (const node &bb) const {return (node){x-bb.x,y-bb.y};}
	db operator * (const node &bb) const {return x*bb.y-bb.x*y;}
}nw;
db K(node aa,node bb){return (bb.y-aa.y)/(bb.x-aa.x);}
multiset<node> sb;
multiset<node>::iterator it,nt,n2;
int n;

int main()
{
    ///
	n=rd(),f[1]=rd();
	for(int i=1;i<=n;++i)
	{
		db a,b,c;
		scanf("%lf%lf%lf",&a,&b,&c);
		f[i]=max(f[i],f[i-1]);
		if(!sb.empty())
		{
			it=sb.begin(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
			it=--sb.end(),f[i]=max(f[i],((*it).y+(*it).x*a/b)*b);
			db l=(*sb.begin()).x+eps,r=(*(--sb.end())).x-eps,ls=1e9;
			while(r-l>eps&&r-l<ls)
			{
				ls=r-l;
				db md=(l+r)/2;
				it=sb.upper_bound((node){md,0});
				if(it==sb.end()) break;
				nt=--it,++it;
				f[i]=max(f[i],max((*it).y+(*it).x*a/b,(*nt).y+(*nt).x*a/b)*b);
				if(K(*it,*nt)>-a/b) l=(*it).x+eps;
				else r=(*nt).x-eps;
			}
		}
		nw=(node){f[i]/(a*c+b)*c,f[i]/(a*c+b)};
		it=sb.insert(nw);
		if(it!=sb.begin()&&it!=(--sb.end()))
		{
			nt=n2=it,--nt,++n2;
			if(((*it)-(*nt))*((*n2)-(*it))>eps){sb.erase(it);continue;}
		}
		if(it!=sb.begin())
		{
			nt=it,--nt;
			if(fabs((*it).x-(*nt).x)<eps)
			{
				if((*it).y<(*nt).y){sb.erase(it);continue;}
				sb.erase(nt);
			}
		}
		if(it!=(--sb.end()))
		{
			n2=it,++n2;
			if(fabs((*it).x-(*n2).x)<eps)
			{
				if((*it).y<(*n2).y){sb.erase(it);continue;}
				sb.erase(n2);
			}
		}
		while(it!=sb.begin()&&it!=(++sb.begin()))
		{
			nt=it,--nt;
			n2=nt,--n2;
			if(((*nt)-(*it))*((*n2)-(*nt))>eps) break;
			sb.erase(nt);
		}
		while(it!=(--sb.end())&&it!=(--(--sb.end())))
		{
			nt=it,++nt;
			n2=nt,++n2;
			if(((*nt)-(*it))*((*n2)-(*nt))<-eps) break;
			sb.erase(nt);
		}
	}
	printf("%.3lf\n",f[n]);
	return 0;
}
posted @ 2020-04-19 22:35  ✡smy✡  阅读(117)  评论(0编辑  收藏  举报