C
发现是把按照x排序后的中间一段点用x轴覆盖,两边的点用y轴覆盖。但算答案有点麻烦,分别是\(min(2mx-mn,mx-2mn)\),沿着x,y轴分别翻转后就只要考虑\(mx-2mn\)了,然后没跨过坐标轴的特判一下;跨过的就考虑:左端点(<0)右移,维护右端点(>0)对应的值,观察
这些值的变化过程,发现是个单调栈的覆盖,每次区间加,用线段树维护即可。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=2e5+5;
const ll F=1e10;
ll A[N];
struct SGT{
ll mn[N<<2],tg[N<<2];
#define mid ((l+r)>>1)
#define lc (u<<1)
#define rc ((u<<1)|1)
void init(int u,int l,int r){
if(l==r){
mn[u]=A[l];
tg[u]=0;
return;
}
init(lc,l,mid); init(rc,mid+1,r);
tg[u]=0;
mn[u]=min(mn[lc],mn[rc])+tg[u];
}
void mdf(int u,ll y){
mn[u]+=y;
tg[u]+=y;
}
void psd(int u,int l,int r){
if(!tg[u]) return;
mdf(lc,tg[u]);
mdf(rc,tg[u]);
tg[u]=0;
}
void upd(int u,int l,int r,int a,int b,ll y){
if(a>b) return;
//if(u==1) cout<<"upd:"<<a<<" "<<b<<" "<<y<<endl;
if(a<=l && r<=b){
mdf(u,y);
return;
}
psd(u,l,r);
if(b>mid) upd(rc,mid+1,r,a,b,y);
if(a<=mid) upd(lc,l,mid,a,b,y);
mn[u]=min(mn[lc],mn[rc])+tg[u];
}
}T;
int n;
struct node{
ll x,y;
}p[N];
bool opt(node u,node v){
return u.x<v.x;
}
bool cmp(node u,node v){
return u.x>v.x;
}
ll ans;
ll cnt(ll l,ll r){
if(l==F) return 0;
if(l>=0) return r;
return r-l-l;
}
void spc(){
vector<node>tmp;
tmp.clear();
ll mn=F,mx=-F;
for(int i=1;i<=n;i++){
if(p[i].x>=0) tmp.push_back(p[i]);
else mn=min(mn,p[i].y),mx=max(mx,p[i].y);
}
sort(tmp.begin(),tmp.end(),cmp);
for(auto u:tmp) {
ans = min(ans,u.x+cnt(mn,mx));
mn=min(mn,u.y); mx=max(mx,u.y);
}
ans=min(ans,cnt(mn,mx));
}
struct seg{
int r;
ll x;
};
void work(){
//puts("work");
spc();
for(int i=1;i<=n;i++) swap(p[i].x,p[i].y);
spc();
for(int i=1;i<=n;i++) swap(p[i].x,p[i].y);
sort(p+1,p+n+1,opt);
//puts("p");
//for(int i=1;i<=n;i++) cout<<p[i].x<<" "<<p[i].y<<endl;
int k=1;
while(p[k].x<0 && k<n) k++;
if(k==1 || p[k].x<0) return;
seg q1[N],q2[N];
ll mx1=0,mx2=0;
int t1=0,t2=0;
for(int i=n;i>=k;i--){
A[i]=mx2*2+mx1+p[i].x;
//cout<<i<<" "<<A[i]<<endl;
if(i==k) break;
if(p[i].y<0){
ll u=-p[i].y;
if(u>mx2) mx2=u,q2[++t2]=(seg){i-1,u};
}
else{
ll u=p[i].y;
if(u>mx1) mx1=u,q1[++t1]=(seg){i-1,u};
}
}
T.init(1,k,n);
mx1=0,mx2=0;
q1[0]=q2[0]=(seg){n,0};
q1[t1+1].r=q2[t2+1].r=k-1;
int l1=0,l2=0;
for(int L=1;L<k;L++){
ll u=T.mn[1]-p[L].x*2;
//cout<<L<<" u="<<u<<" "<<T.mn[1]<<" "<<p[L].x<<endl;
ans=min(ans,u);
if(p[L].y<0){
ll u=-p[L].y;
if(u>mx2){
T.upd(1,k,n,q2[l2+1].r+1,n,2ll*(u-mx2) );
mx2=u;
while(l2<t2 && u>q2[l2+1].x){
l2++;
//cout<<" ! "<<q2[l2+1].r+1<<" "<<q2[l2].r<<" "<<2ll*(u-q2[l2].x)<<endl;
T.upd(1,k,n,q2[l2+1].r+1,q2[l2].r,2ll*(u-q2[l2].x));
}
}
}
else{
ll u=p[L].y;
if(u>mx1){
T.upd(1,k,n,q1[l1+1].r+1,n,1ll*(u-mx1) );
mx1=u;
while(l1<t1 && u>q1[l1+1].x){
l1++;
//cout<<" ! "<<q1[l1+1].r+1<<" "<<q1[l1].r<<" "<<1ll*(u-q1[l1].x)<<endl;
T.upd(1,k,n,q1[l1+1].r+1,q1[l1].r,1ll*(u-q1[l1].x));
}
}
}
}
}
void Work(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%lld%lld",&p[i].x,&p[i].y);
ans=F;
work();
for(int i=1;i<=n;i++) p[i].x=-p[i].x;
work();
for(int i=1;i<=n;i++) p[i].y=-p[i].y;
work();
for(int i=1;i<=n;i++) p[i].x=-p[i].x;
work();
cout<<ans<<endl;
}
int main()
{
//srand(time(0));
//freopen("1.in","r",stdin);
//freopen("1.out","w",stdout);
int T; cin>>T; while(T--) Work();
return 0;
}
- ACM-ICPC Regional Contest Nanjing 2020acm-icpc regional contest nanjing regional contest nanjing 2022 regional contest nanjing 2023 yesterday regional contest nanjing acm-icpc regional contest seoul inscryption regional contest nanjing nanjing regional contest grand programming acm-icpc american regional the universal acm-icpc regional subregional programming acm-icpc contest