Description
Input
Output
Sample Input
样例输入1
10 10 4
1 6
4 1
6 9
9 4
样例输入2
10 10 4
2 2
4 4
7 7
9 9
Sample Output
样例输出1
32
样例输出2
26
Data Constraint
Solution
- 先贴上原题题解:
为方便统计答案,先加入两个边界点 (0,0) 和 (w,h) 。
之后将所有点按 X 坐标从小到大排序。
我们对于直线
l:y=h2 ,上下同时维护各一个值远离逐渐 l 的单调栈。栈中存着许多线段,线段树中存着两个栈元素纵坐标的相反数
−Y1−Y2 ,则取出后加上 h 就是对应矩形的宽了。
其中 zjp_shadow的博客 讲的很详细:
(虚线 为中线,黑色 是当前单调栈里的,红色 是现在将过来的一个线段)
我们将两个栈顶线段的答案进行更改,将这些线段的横着的答案变小它坐标的相应的差值。
这个就可以直接在线段树上做加减法就行了。
然后我们用这条 绿色 和 红色 的线段一起,共同构成一个新的线段存进单调栈中去。
为了同时得到矩形的长,我们把值在减去当前的横坐标
Xi ,之后在查询时加上目前的横坐标 Xi+1 ,这样就得出了对应矩形的长 Xi+1−Xi 。
这样也就得到了当前矩形一半周长的最优答案。
注意每做完一个点 i 时,要及时更新答案,并将
i 点的信息单点加到线段树上。为了避免 i+1 不能成功进入栈中,需要在栈末尾加入一个极值点 (i,h/0) 来保证入栈。
而对于直线 x=w2 也同理,交换坐标再做一遍即可。
时间复杂度 O(N log N) 。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=2e5+5;
struct data
{
int x,y;
}a[N],f[N<<2],st1[N]/*down*/,st2[N]/*up*/;
int w,h,n,ans;
int top1,top2,qx,qy,qz;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
inline bool cmp(data x,data y)
{
return x.x<y.x;
}
inline int max(int x,int y)
{
return x>y?x:y;
}
void change(int v,int l,int r)
{
if(qx<=l && r<=qy)
{
f[v].x+=qz;
f[v].y+=qz;
return;
}
int mid=l+r>>1;
if(qx<=mid) change(v<<1,l,mid);
if(qy>mid) change(v<<1|1,mid+1,r);
f[v].x=max(f[v<<1].x,f[v<<1|1].x)+f[v].y;
}
inline void solve()
{
memset(f,top1=top2=0,sizeof(f));
sort(a+1,a+1+n,cmp);
for(int i=1;i<n;i++)
{
if(a[i].y<=h>>1)
{
int t=i-1;
while(top1 && st1[top1].y<a[i].y)
{
qx=st1[top1].x,qy=t,qz=st1[top1].y-a[i].y;
change(1,1,n);
t=st1[top1--].x-1;
}
if(t^i-1) st1[++top1]=(data){t+1,a[i].y};
}else
{
int t=i-1;
while(top2 && st2[top2].y>a[i].y)
{
qx=st2[top2].x,qy=t,qz=a[i].y-st2[top2].y;
change(1,1,n);
t=st2[top2--].x-1;
}
if(t^i-1) st2[++top2]=(data){t+1,a[i].y};
}
st1[++top1]=(data){i,0};
st2[++top2]=(data){i,h};
qx=qy=i,qz=h-a[i].x;
change(1,1,n);
ans=max(ans,f[1].x+a[i+1].x);
}
}
int main()
{
w=read(),h=read(),n=read();
for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
a[++n]=(data){0,0};
a[++n]=(data){w,h};
solve();
for(int i=1;i<=n;i++) swap(a[i].x,a[i].y);
swap(w,h);
solve();
printf("%d",ans<<1);
return 0;
}