Loading

CF1470F

显然只会存在 \(3\) 种本质不同的方式选择两个矩形。

  1. 两个矩形不相交。

这种情况可以直接遍历所有平行 \(x/y\) 轴的分割线,使选取的两个矩形分别在分割线的两边。分别找出极值点直接计算即可。

  1. 相交成一个十字。

可以发现此时两个矩形都至少有两条边在恰好包含所有点的大矩形的边界上。

因此,为了有效找出这样的矩形,考虑遍历“竖”矩形的右边界。令 \(L_d\) 为“竖”矩形左边界左侧点最小 \(y\) 坐标,\(L_u\) 为左边界左侧点最大 \(y\) 坐标,同理定义右边界右侧点的 \(R_u,R_d\)

假设 \(R_u\ge L_u\)。在 \(L_d\ge R_d\) 的前缀上,直接选择最右的边界。而在剩下的子区间将会满足 \(L_u\le R_u,L_d\le R_d\)。假设矩形固定的边界为 \(L,R\),则总面积为 \((R_u-L_d)\cdot H+(R-L)\cdot W\),其中 \(H\) 表示大矩形的长度,\(W\) 表示大矩形的高度。改一下就可以得到:\((R\cdot W+R_u\cdot H)-(L\cdot W+L_d\cdot H)\),线段树维护一下区间最值即可。

  1. 两个矩形各自有一个顶点在另一个矩形内部。

可以发现此时这两个矩形一定各有一个角与大矩形的某个角重合,即这两个分别覆盖对角,总共只有覆盖左上角和右下角以及覆盖左下角覆盖右上角两种情况。

假设是覆盖左上和右下。考虑遍历 \(x\) 轴,求出前缀 \(y\) 的最小值和后缀最大值。然后直接暴力枚举点对就是 $\mathcal O (n^2) $ 的,考虑优化。可以发现由于要满足两个矩形相交,因此对于每个左上矩形右下角点,所对应右下矩形左上角点的就是一段区间,维护区间静态凸包即可。

#include<bits/stdc++.h>
#define R(i,a,b) for(int i=(a),i##E=(b);i<=i##E;i++)
#define L(i,a,b) for(int i=(b),i##E=(a);i>=i##E;i--)
using namespace std;
const int N=222222;

int n;
long long ans,v[N];
pair<int,int>p[N];
void calc1()
{
	sort(p+1,p+n+1);
	R(i,0,n+5) v[i]=0;
	int mny=p[1].second,mxy=p[1].second;
	R(i,2,n) 
	{
		mny=min(mny,p[i].second);
		mxy=max(mxy,p[i].second);
		v[i]=1ll*(p[i].first-p[1].first)*(mxy-mny);
	}
	mny=p[n].second,mxy=p[n].second;
	L(i,1,n-1) 
	{
		mny=min(mny,p[i].second);
		mxy=max(mxy,p[i].second);
		v[i-1]+=1ll*(p[n].first-p[i].first)*(mxy-mny);
	}
	R(i,0,n) ans=min(ans,v[i]);
}
int Ld[N],Lu[N],Rd[N],Ru[N];

template<class Callable>

void solveofcalc2(int L,int R,int l,int r,Callable cc)
{
	int mid=(l+r)>>1;
	long long mn=3e18;
	int mnp=0;
	R(i,L,R) 
	{
		long long tp=cc(i,mid);
		if(tp<mn) mn=tp,mnp=i;
	}
	v[mid]=mn;
	if(l!=r) solveofcalc2(mnp,R,l,mid,cc),solveofcalc2(L,mnp,mid+1,r,cc);
}
void calc2()
{
	sort(p+1,p+n+1);
	R(i,0,n+5) v[i]=0;
	int mny=1e9,mnyp=0,mxy=-1e9,mxyp=0,mxx=-1e9,mnx=1e9;
	R(i,1,n) 
	{
		if(p[i].second<=mny) mny=p[i].second,mnyp=i;
		if(p[i].second>=mxy) mxy=p[i].second,mxyp=i;
		mxx=max(mxx,p[i].first);
		mnx=min(mnx,p[i].first);
	}
	Ld[0]=1e9,Lu[0]=-1e9;
	Rd[n+1]=1e9,Ru[n+1]=-1e9;
	R(i,1,n) Ld[i]=min(Ld[i-1],p[i].second),Lu[i]=max(Lu[i-1],p[i].second);
	L(i,1,n) Rd[i]=min(Rd[i+1],p[i].second),Ru[i]=max(Ru[i+1],p[i].second);
	if(mnyp>mxyp) swap(mnyp,mxyp);
	auto cc=[&](int x,int y)
	{
		if(x==1&&y==n) return 1ll*(p[y].first-p[x].first)*(mxy-mny);
		return 1ll*(p[y].first-p[x].first)*(mxy-mny)+1ll*(max(Ru[y+1],Lu[x-1])-min(Rd[y+1],Ld[x-1]))*(mxx-mnx);
	};
	solveofcalc2(1,mnyp,mxyp,n,cc);
	R(i,mxyp,n) ans=min(ans,v[i]);
}
int L1[N],L2[N],L3[N],L4[N];
int q[N];
pair<int,int>pq[N];
inline bool cmp(pair<int,int>x,pair<int,int>y)
{
	if(!x.second&&!y.second) return x.first<y.first;
	if((!x.second)^(!y.second)) return !x.second;
	if(!x.first&&!y.first) return x.second<y.second;
	if(1ll*x.first*y.second!=1ll*y.first*x.second) return 1ll*x.first*y.second>1ll*y.first*x.second;
	return x.first<y.first;
}
inline long long calc(pair<int,int>x,pair<int,int>y)
{
	return 1ll*x.first*y.first+1ll*x.second*y.second;
}

struct segt
{
	int rt[N<<2],nd;
	int ls[5555555],rs[5555555];
	pair<int,int> t[5555555];
	void build(int l,int r,int x)
	{
		rt[x]=0;
		if(l==r) return;
		int mid=(l+r)>>1;
		build(l,mid,x<<1);
		build(mid+1,r,x<<1|1);
	}	
	void init(int n)
	{
		R(i,0,nd) ls[i]=rs[i]=0,t[i]=pair<int,int>(0,0);
		nd=0;
		build(1,n,1);
	}
	void insert(int l,int r,pair<int,int> v,int &x)
	{
		if(!x) 
		{
			x=++nd;
			t[x]=v;
			return;
		}
		int mid=(l+r)>>1;
		if(calc(t[x],pq[mid])>calc(v,pq[mid])) swap(t[x],v);
		if(calc(t[x],pq[l])>calc(v,pq[l])) insert(l,mid,v,ls[x]);
		if(calc(t[x],pq[r])>calc(v,pq[r])) insert(mid+1,r,v,rs[x]);
	}
	void insert(int p,int l,int r,pair<int,int> v,int x)
	{
		insert(1,n,v,rt[x]);
		if(l==r) return;
		int mid=(l+r)>>1;
		if(p<=mid) insert(p,l,mid,v,x<<1);
		else insert(p,mid+1,r,v,x<<1|1);
	}
	void query(int p,int l,int r,int x)
	{
		if(!x) return;
		ans=min(ans,calc(t[x],pq[p]));
		int mid=(l+r)>>1;
		if(p<=mid) query(p,l,mid,ls[x]);
		if(mid<p) query(p,mid+1,r,rs[x]);
	}
	void query(int L,int R,int l,int r,int x,int k)
	{
		if(L<=l&&r<=R) return query(k,1,n,rt[x]);
		int mid=(l+r)>>1;
		if(L<=mid) query(L,R,l,mid,x<<1,k);
		if(mid<R) query(L,R,mid+1,r,x<<1|1,k);
	}
}st;
void calc3()
{
	int Mny=1e9,Mxy=-1e9;
	sort(p+1,p+n+1);
	R(i,1,n) Mny=min(Mny,p[i].second),Mxy=max(Mxy,p[i].second);
	int mny=Mxy,mxy=Mny;
	R(i,1,n) L1[i]=p[i].first-p[1].first,L2[i]=mxy-Mny,mxy=max(mxy,p[i].second);
	L(i,1,n) L3[i]=p[n].first-p[i].first,L4[i]=Mxy-mny,mny=min(mny,p[i].second);
	q[0]=0;
	R(i,1,n) q[i]=L2[i];
	sort(q+1,q+n+1);
	R(i,1,n) pq[i]=(L1[i]+L4[i]?pair<int,int>(L1[i],L4[i]):pair<int,int>(1,1));
	sort(pq+1,pq+n+1,cmp);
	st.init(n);
	R(i,1,n)
	{
		int p=lower_bound(q+1,q+n+1,L2[i])-q;
		st.insert(p,1,n,pair<int,int>(L2[i],L3[i]),1);
		p=lower_bound(q+1,q+n+1,Mxy-Mny-L4[i])-q;
		if(L1[i]||L4[i])
		{
			int pp=lower_bound(pq+1,pq+n+1,pair<int,int>(L1[i],L4[i]),cmp)-pq;
			if(p!=n+1) st.query(p,n,1,n,1,pp);
		}
	}
}
void solve()
{
	ans=1e18;
	cin>>n;
	R(i,1,n) cin>>p[i].first>>p[i].second;
	calc1();
	R(i,1,n) swap(p[i].first,p[i].second);
	calc1();
	R(i,1,n) swap(p[i].first,p[i].second);
	calc2();
	calc3();
	R(i,1,n) p[i].second=1e9-p[i].second;
	calc3();
	cout<<ans<<'\n';
}
signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	int _;
	cin>>_;
	while(_--) solve();

}

posted @ 2024-01-19 00:10  yoisaki_hizeci  阅读(24)  评论(0)    收藏  举报