2020-2021 ACM-ICPC, Asia Nanjing Regional Contest

发布时间 2023-05-16 21:46:07作者: sz[sz]

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;
}

线段树的tg没有初始化,调了一年。。。 # J