题解 Paint
在思维不连贯的时候调题就是浪费时间
我改这题用的时间严格长于改 T3
首先发现就是要找周长最长的内部不含其他点的矩形
枚举最左边界,扫描右边界,set 中维护相邻元素的最大差值可以做到 \(O(n^2\log n)\)
将加点改为删点,右→左扫描右边界+链表可以做到 \(O(n^2)\)
发现一个性质:
最优的矩形一定跨过 \(\frac{w}{2}\) 或 \(\frac{h}{2}\)
证明考虑它蜷缩在一个角上肯定没有选择一个肯定能达到的下界 \(2(\max(w, h)+1)\) 优
那么利用这个性质
枚举上边界,离散化后线段树上维护出每个下边界 \(i\) 的答案
发现就是 \(y_u-y_i+\min\{t:x_t>\frac{w}{2}\}-\max\{s:x_s\leqslant\frac{w}{2}\}\)
那么这个 \(s, t\) 可以在移动上边界时对左右两边分别维护单调栈
于是转化成了一些区间加减,有亿些细节
复杂度 \(O(n\log n)\)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define fir first
#define sec second
#define ll long long
#define int long long
char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
int ans=0, f=1; char c=getchar();
while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
return ans*f;
}
int w, h, n;
int x[N], y[N], ans;
pair<int, int> p[N];
namespace force{
int bin[N], ans;
void solve() {
int lim=1<<(n*2), mask=3;
for (int i=0; i<n; ++i) bin[i]=i<<1;
for (int s=0; s<lim; ++s) {
int l=0, r=w, d=0, u=h;
for (int i=0; i<n; ++i) {
int tem=(s>>bin[i])&mask;
if (tem==0) r=min(r, x[i]);
else if (tem==1) l=max(l, x[i]);
else if (tem==2) u=min(u, y[i]);
else d=max(d, y[i]);
}
if (l==r || d==u) continue;
else ans=max(ans, (r-l + u-d)<<1);
}
cout<<ans<<endl;
}
}
namespace task1{
int ans;
void solve() {
x[n]=0; y[n]=1; ++n;
x[n]=1; y[n]=0; ++n;
x[n]=w; y[n]=1; ++n;
x[n]=1; y[n]=h; ++n;
for (int i=0; i<n; ++i) {
for (int j=0; j<n; ++j) if (x[j]>x[i]) {
for (int k=0; k<n; ++k) if (x[k]>x[i] && x[k]<x[j] && y[k]>max(y[i], y[j])) {
int maxn=-1;
for (int l=0; l<n; ++l) if (x[l]>x[i] && x[l]<x[j] && y[l]<y[k]) {
maxn=max(maxn, y[l]);
}
if (~maxn) ans=max(ans, (x[j]-x[i] + y[k]-maxn)<<1);
}
}
}
cout<<ans<<endl;
}
}
namespace task{
pair<int, int> lsta[N], rsta[N];
int uni[N], ltop, rtop, usiz;
int tl[N<<2], tr[N<<2], val[N<<2], tag[N<<2];
#define tl(p) tl[p]
#define tr(p) tr[p]
#define pushup(p) val[p]=max(val[p<<1], val[p<<1|1])
void spread(int p) {
if (!tag[p]) return ;
val[p<<1]+=tag[p]; tag[p<<1]+=tag[p];
val[p<<1|1]+=tag[p]; tag[p<<1|1]+=tag[p];
tag[p]=0;
}
void build(int p, int l, int r) {
tl(p)=l; tr(p)=r; val[p]=tag[p]=0;
if (l==r) return ;
int mid=(tl(p)+tr(p))>>1;
build(p<<1, l, mid);
build(p<<1|1, mid+1, r);
pushup(p);
}
void upd(int p, int l, int r, int dat) {
if (l<=tl(p)&&r>=tr(p)) {val[p]+=dat; tag[p]+=dat; return ;}
spread(p);
int mid=(tl(p)+tr(p))>>1;
if (l<=mid) upd(p<<1, l, r, dat);
if (r>mid) upd(p<<1|1, l, r, dat);
pushup(p);
}
// void upd(int p, int l, int r, int dat) {for (int i=l; i<=r; ++i) val[i]+=dat;}
// int query() {int ans=0; for (int i=0; i<=usiz; ++i) ans=max(ans, val[i]); return ans;}
void solve() {
ltop=rtop=usiz=0;
for (int i=1; i<=n; ++i) uni[++usiz]=p[i].sec;
sort(uni+1, uni+usiz+1);
usiz=unique(uni+1, uni+usiz+1)-uni-1;
build(1, 0, usiz);
for (int i=0; i<=usiz; ++i) val[i]=0;
sort(p+1, p+n+1, [](pair<int, int> a, pair<int, int> b){return a.sec<b.sec;});
int pos=1;
// for (int i=1; i<=n; ++i) cout<<"("<<p[i].fir<<','<<p[i].sec<<") "; cout<<endl;
// cout<<"uni: "; for (int i=1; i<=usiz; ++i) cout<<uni[i]<<' '; cout<<endl;
for (int i=1; i<=usiz; ++i) {
// cout<<"i: "<<i<<endl;
upd(1, 0, i-1, uni[i]-uni[i-1]);
ans=max(ans, val[1]<<1);
// cout<<"val: "; for (int j=1; j<=usiz; ++j) cout<<val[j]<<' '; cout<<endl;
// ans=max(ans, query()<<1);
// cout<<"lsta: "; for (int j=1; j<=ltop; ++j) cout<<"("<<lsta[j].fir<<','<<lsta[j].sec<<") "; cout<<endl;
// cout<<"rsta: "; for (int j=1; j<=rtop; ++j) cout<<"("<<rsta[j].fir<<','<<rsta[j].sec<<") "; cout<<endl;
while (pos<=n && p[pos].sec==uni[i]) {
if (p[pos].fir<=w/2) {
int inc=i;
while (ltop && lsta[ltop].fir<=p[pos].fir) {
upd(1, lsta[ltop].sec, inc-1, lsta[ltop].fir-p[pos].fir); //, cout<<"decrease: "<<lsta[ltop].fir-p[pos].fir<<endl;
inc=lsta[ltop--].sec;
}
lsta[++ltop]={p[pos].fir, inc};
}
else {
int inc=i;
while (rtop && rsta[rtop].fir>=p[pos].fir) {
upd(1, rsta[rtop].sec, inc-1, p[pos].fir-rsta[rtop].fir); //, cout<<"decrease: "<<p[pos].fir-rsta[rtop].fir<<endl;
inc=rsta[rtop--].sec;
}
rsta[++rtop]={p[pos].fir, inc};
}
++pos;
}
// cout<<"after_lsta: "; for (int j=1; j<=ltop; ++j) cout<<"("<<lsta[j].fir<<','<<lsta[j].sec<<") "; cout<<endl;
// cout<<"after_rsta: "; for (int j=1; j<=rtop; ++j) cout<<"("<<rsta[j].fir<<','<<rsta[j].sec<<") "; cout<<endl;
upd(1, i, i, w);
if (lsta[ltop].fir!=0) lsta[++ltop]={0, i};
if (rsta[rtop].fir!=w) rsta[++rtop]={w, i};
}
}
}
signed main()
{
freopen("paint.in", "r", stdin);
freopen("paint.out", "w", stdout);
w=read(); h=read(); n=read();
for (int i=1; i<=n; ++i) x[i]=read(), y[i]=read(), p[i]={x[i], y[i]};
++n; x[n]=w; y[n]=h; p[n]={0, 0};
++n; x[n]=w; y[n]=h; p[n]={w, h};
// if (n<=10) force::solve();
// else task1::solve();
task::solve();
swap(w, h);
for (int i=1; i<=n; ++i) swap(x[i], y[i]), swap(p[i].fir, p[i].sec);
task::solve();
cout<<ans<<endl;
return 0;
}