[DS记录]AT2149 [ARC063D] すぬけ君の塗り絵 2 / Snuke's Coloring 2

command_block

2021-05-13 09:07:57

Personal

**题意** : 平面上有一个左下角坐标 $(0,0)$ 右上角坐标 $(W,H)$ 的矩形,起初长方形内部被涂白。 现在给定 $n$ 个点,你每次在以下 $4$ 种操作中选择一种: - 将矩形内 $x>x_i$ 的区域涂黑 - 将矩形内 $x<x_i$ 的区域涂黑 - 将矩形内 $y<y_i$ 的区域涂黑 - 将矩形内 $y>y_i$ 的区域涂黑 不难发现,最后剩下的白色部分是一个矩形,最大化该矩形的周长。 $n\leq 3\times 10^5$ ,时限$\texttt{4s}$。 ------------ 题意不难转化为 : 求一个周长最大的矩形,使得内部没有特殊点。 考虑分治,每次处理经过 $y=m$ 的矩形。 对于某个给定的 $x$ 的区间,矩形的高是容易确定的,只需要得到两侧距离的 $\min$ 即可。 进一步对 $x$ 进行分治,当处理跨越 $x=c$ 的贡献时,根据单调性不难做到线性。 (具体地,需要双指针和单调队列) 两个分治嵌套,复杂度为 $O(n\log^2n)$。 不难发现, $1\times H,\ W\times 1$ 的矩形总是能够被选出的。 于是,作为最优答案的矩形必然经过 $y=H/2$ 或者 $x=W/2$ ,否则周长比不过上面两个。 这样,两次分治即可做到 $O(n\log n)$。 ```cpp #include<algorithm> #include<cstdio> #define MaxN 300500 using namespace std; int l1,l2,x[MaxN],y1[MaxN],y2[MaxN],sy1[MaxN],sy2[MaxN] ,o1[MaxN],o2[MaxN],o3[MaxN],ans; struct MQueue{ int q[MaxN],ql,qr,*x; void Init(int *tx){x=tx;ql=1;qr=0;} void push(int i){ while(ql<=qr&&x[q[qr]]<x[i])qr--; q[++qr]=i; } int qry(int lim){ while(ql<=qr&&q[ql]<=lim)ql++; return ql<=qr ? x[q[ql]] : 0; } }Q1,Q2; void solve(int l,int r) { if (l==r){ ans=max(ans,y1[l]+y2[l]+x[l+1]-x[l-1]); return ; }int mid=(l+r)>>1; solve(l,mid);solve(mid+1,r); sy1[mid]=l2/2;sy2[mid]=(l2+1)/2; for (int i=mid+1;i<=r;i++){ sy1[i]=min(sy1[i-1],y1[i]); sy2[i]=min(sy2[i-1],y2[i]); } o3[r+1]=0; for (int i=r;i>mid;i--){ o1[i]=sy1[i]+x[i+1];o2[i]=sy2[i]+x[i+1]; o3[i]=max(o3[i+1],x[i+1]+sy1[i]+sy2[i]); } Q1.Init(o1);Q2.Init(o2); for (int i=mid,ty1=l2/2,ty2=(l2+1)/2,p1=mid,p2=mid;i>=l;i--){ ty1=min(ty1,y1[i]);ty2=min(ty2,y2[i]); while(p1<r&&y1[p1+1]>=ty1)Q2.push(++p1); while(p2<r&&y2[p2+1]>=ty2)Q1.push(++p2); ans=max(ans,x[min(p1,p2)+1]-x[i-1]+ty1+ty2); ans=max(ans,o3[max(p1,p2)+1]-x[i-1]); ans=max(ans,Q1.qry(p1)+ty2-x[i-1]); ans=max(ans,Q2.qry(p2)+ty1-x[i-1]); } } struct Point{int x,y;}p[MaxN]; bool cmp(const Point &A,const Point &B) {return A.x<B.x;} int tn,n; void calc() { sort(p+1,p+n+1,cmp); tn=0; for (int i=1;i<=n;i++){ int ty=p[i].y-l2/2; if (i>1&&p[i].x==p[i-1].x){ if (ty<0)y1[tn]=min(y1[tn],-ty); else y2[tn]=min(y2[tn],ty); }else { x[++tn]=p[i].x; if (ty<0){y1[tn]=-ty;y2[tn]=(l2+1)/2;} else {y1[tn]=l2/2;y2[tn]=ty;} } }x[tn+1]=l1; for (int i=1;i<=tn;i++) ans=max(ans,l2+x[i+1]-x[i]); solve(1,tn); } int main() { scanf("%d%d%d",&l1,&l2,&n); for (int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y); calc(); for (int i=1;i<=n;i++) swap(p[i].x,p[i].y); swap(l1,l2);calc(); printf("%d",ans*2); return 0; } ```