传送门
题意:
目前有一个左下角(0,0)(0,0)(0,0)右上角(W,H)(W,H)(W,H)的矩形,起初矩形内部都是白色的。
现在给你nnn个点,每次在以下操作中选择一种:
- 将矩形x<xix<x_ix<xi的区域染黑
- 将矩形x>xix>x_ix>xi的区域染黑
- 将矩形y<yiy<y_iy<yi的区域染黑
- 将矩形y>yiy>y_iy>yi的区域染黑
现在需要最大化操作后的白色矩阵的周长。
1≤W,H≤1e8,1≤n≤3e51\le W,H\le 1e8,1\le n\le 3e51≤W,H≤1e8,1≤n≤3e5
思路:
首先可以发现答案至少是max(W,H)∗2+2max(W,H)*2+2max(W,H)∗2+2,让后可以发现答案矩形一定需要跨过xxx或yyy的中轴线,
两种情况无非转一下坐标轴,下面只考虑跨过yyy中轴线的情况。
首先按xxx坐标排序,一种暴力的想法就是枚举两个位置(j,i)(j,i)(j,i),让后答案就是xi−xj+max(yj,i)−min(yj,i)x_i-x_j+max(y_{j,i})-min(y_{j,i})xi−xj+max(yj,i)−min(yj,i)。由于要跨过yyy轴,考虑将yyy坐标分成两类,yi≤H/2y_i\le H/2yi≤H/2以及yi>H/2y_i>H/2yi>H/2,对于yi>H/2y_i>H/2yi>H/2的部分,不难发现可以用单调栈维护答案,维护一个单调递增的栈即可,让后弹出的时候将矩形多出来的高减掉即可。对于yi≤H/2y_i\le H/2yi≤H/2的部分,维护单调递减的栈,同样的操作。
具体实现起来细节还是蛮多的,注意边界问题,还有修改的时候该哪些点。。
#include<bits/stdc++.h>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define Mid (tr[u].l+tr[u].r>>1)
#define pb push_back
using namespace std;const int N=1000010,INF=0x3f3f3f3f,mod=1e9+7;
typedef long long LL;int W,H,n;
struct Point {int x,y;bool operator < (const Point &W) const {return x<W.x;}
}p[N];
struct Stack {int x,val;
}stk1[N],stk2[N];
int top1,top2;
struct Node {int l,r;LL mx,lazy;
}tr[N<<2];void pushup(int u) {tr[u].mx=max(tr[L].mx,tr[R].mx);
}void tag(int u,LL lazy) {tr[u].lazy+=lazy;tr[u].mx+=lazy;
}void pushdown(int u) {tag(L,tr[u].lazy);tag(R,tr[u].lazy);tr[u].lazy=0;
}void build(int u,int l,int r) {tr[u]={l,r,0,0};if(l==r) {tr[u].mx=-p[l].x+H;return;}build(L,l,Mid); build(R,Mid+1,r);pushup(u);
}void change(int u,int l,int r,LL x) {if(l>r) return;if(tr[u].l>=l&&tr[u].r<=r) {tr[u].mx+=x;tr[u].lazy+=x;return;}pushdown(u);if(l<=Mid) change(L,l,r,x);if(r>Mid) change(R,l,r,x);pushup(u);
}LL query(int u,int l,int r) {if(tr[u].l>=l&&tr[u].r<=r) return tr[u].mx;pushdown(u);LL ans=0;if(l<=Mid) ans=max(ans,query(L,l,r));if(r>Mid) ans=max(ans,query(R,l,r));return ans;
}void up(int x,LL val) {while(top1>1&&stk1[top1].val>val) {auto u=stk1[top1--];change(1,stk1[top1].x,u.x-1,-(u.val-val));}stk1[++top1]={x,(int)val};
}void down(int x,LL val) {while(top2>1&&stk2[top2].val<val) {auto u=stk2[top2--];change(1,stk2[top2].x,u.x-1,(u.val-val));//cout<<"y:"<<u.val-val<<endl;}stk2[++top2]={x,(int)val};
}LL run() {top1=top2=0;p[0]={0,H/2};p[n+1]={W,H};stk1[++top1]={0,H/2};stk2[++top2]={0,H/2};sort(p+1,p+1+n);build(1,0,n+1);LL ans=0;for(int i=1;i<=n+1;i++) {ans=max(ans,query(1,0,i-1)+p[i].x);//cout<<"ans:"<<i<<' '<<ans<<" "<<p[i].x<<endl;if(p[i].y>H/2) {change(1,stk1[top1].x,i-1,-(H-p[i].y));up(i,p[i].y);down(i,0);} else {change(1,stk2[top2].x,i-1,-p[i].y);up(i,H);down(i,p[i].y);}//cout<<"stk"<<top1<<' '<<top2<<endl;}return ans;
}void solve() {scanf("%d%d%d",&W,&H,&n);for(int i=1;i<=n;i++) scanf("%d%d",&p[i].x,&p[i].y);long long ans=run();swap(W,H);for(int i=1;i<=n;i++) swap(p[i].x,p[i].y);//ans=max(ans,run());printf("%lld\n",ans*2);
}int main() {int _=1;while(_--) {solve();}return 0;
}