[ARC063F] Snuke's Coloring 2

昨天毒瘤场遇到这题被腐乳了,发现了必经过中线的性质还是没想清楚怎么统计,实在是太菜太菜

首先很容易转化题意为:找一个周长最大的矩形,满足其内部(不包括边界)上没有任何一个给定点

有一个很重要的观察就是因为答案不小于 \(2\times (\max(W,H)+1)\),因此按照两条中线 \(x=\frac{W}{2}\)\(y=\frac{H}{2}\) 将外面的矩形分成四份后,答案不可能只在其中一个小矩形内

因此我们考虑分别计算跨越两条中线的答案,以下以跨越 \(y=\frac{H}{2}\) 为例,另一种情况很容易通过交换坐标处理

先将所有点按照 \(x\) 坐标排序,先考虑一个暴力的做法,枚举最终矩形的左右边界 \(x_i,x_j\ (i<j)\)

特判掉 \(j-i=1\) 的情形,此时纵坐标取值范围为 \([0,H]\),接下来只考虑 \(j-i\ge 2\) 的情形

对于 \(k\in[i+1,j-1]\),若 \(y_k\le \frac{H}{2}\),则它相当于确定了当前矩形的下边界;同理若 \(y_k> \frac{H}{2}\),则它相当于确定了当前矩形的上边界

具体地,若 \(y_k\le \frac{H}{2}\) 我们令 \(l_k=y_k,r_k=H\);若 \(y_k> \frac{H}{2}\) 我们令 \(l_k=0,r_k=y_k\)

此时一对 \(i,j\) 对答案的贡献为 \(2\times (x_j-x_i+\min_\limits{i+1\le k\le j-1} r_k-\max_\limits{i+1\le k\le j-1} l_k)\)

考虑固定右端点,则 \(\min,\max\) 的贡献的变化是一段一段区间的形式,分别用单调栈维护一下,再把式子放到线段树上求一个最值即可

总复杂度 \(O(n\log n)\)

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<utility>
#include<stack>
#define RI register int
#define CI const int&
#define fi first
#define se second
using namespace std;
typedef pair <int,int> pi;
const int N=300005;
int n,W,H; pi p[N];
class Segment_Tree
{
	private:
		int mx[N<<2],tag[N<<2];
		inline void pushup(CI now)
		{
			mx[now]=max(mx[now<<1],mx[now<<1|1]);
		}
		inline void apply(CI now,CI mv)
		{
			mx[now]+=mv; tag[now]+=mv;
		}
		inline void pushdown(CI now)
		{
			if (tag[now]) apply(now<<1,tag[now]),apply(now<<1|1,tag[now]),tag[now]=0;
		}
	public:
		#define TN CI now=1,CI l=0,CI r=n
		#define LS now<<1,l,mid
		#define RS now<<1|1,mid+1,r
		inline void build(TN)
		{
			mx[now]=tag[now]=0; if (l==r) return;
			int mid=l+r>>1; build(LS); build(RS);
		}
		inline void modify(CI beg,CI end,CI mv,TN)
		{
			if (beg>end) return; if (beg<=l&&r<=end) return apply(now,mv); int mid=l+r>>1; pushdown(now);
			if (beg<=mid) modify(beg,end,mv,LS); if (end>mid) modify(beg,end,mv,RS); pushup(now);
		}
		inline int query(CI beg,CI end,TN)
		{
			if (beg<=l&&r<=end) return mx[now]; int mid=l+r>>1,ret=0; pushdown(now);
			if (beg<=mid) ret=max(ret,query(beg,end,LS)); if (end>mid) ret=max(ret,query(beg,end,RS)); return ret;
		}
		#undef TN
		#undef LS
		#undef RS
}SEG;
inline int solve(int ret=0)
{
	sort(p+1,p+n+1); SEG.build();
	stack <pi> up,dn; up.push(pi(0,0)); dn.push(pi(0,0));
	auto insdn=[&](CI pos,CI val)
	{
		while (dn.size()>1&&dn.top().se<val)
		{
			auto [lp,lv]=dn.top(); dn.pop();
			SEG.modify(dn.top().fi,lp-1,lv);
		}
		SEG.modify(dn.top().fi,pos-1,-val);
		dn.push(pi(pos,val));
	};
	auto insup=[&](CI pos,CI val)
	{
		while (up.size()>1&&up.top().se>val)
		{
			auto [lp,lv]=up.top(); up.pop();
			SEG.modify(up.top().fi,lp-1,-lv);
		}
		SEG.modify(up.top().fi,pos-1,val);
		up.push(pi(pos,val));
	};
	for (RI i=1;i<=n;++i)
	{
		if (p[i-1].se*2<=H)
		{
			insdn(i-1,p[i-1].se);
			insup(i-1,H);
		}
		else
		{
			insdn(i-1,0);
			insup(i-1,p[i-1].se);
		}
		SEG.modify(i-1,i-1,-p[i-1].fi);
		ret=max(ret,p[i].fi-p[i-1].fi+H);
		if (i-2>=0) ret=max(ret,p[i].fi+SEG.query(0,i-2));
	}
	return ret;
}
int main()
{
	RI i; scanf("%d%d%d",&W,&H,&n);
	for (i=1;i<=n;++i) scanf("%d%d",&p[i].fi,&p[i].se);
	p[++n]=pi(W,H); int ans=solve(); swap(W,H);
	for (i=1;i<=n;++i) swap(p[i].fi,p[i].se);
	ans=max(ans,solve());
	return printf("%d",ans*2),0;
}
posted @ 2024-07-14 19:13  空気力学の詩  阅读(2)  评论(0编辑  收藏  举报