专栏文章

题解:P2248 分段

P2248题解参与者 2已保存评论 1

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
1 条
当前快照
1 份
快照标识符
@mimzp6or
此快照首次捕获于
2025/12/01 18:11
3 个月前
此快照最后确认于
2025/12/01 18:11
3 个月前
查看原文
在想到下面的做法前先猜了一波这题有决策单调性(实际上没有),写完交上去获得了目前本题所有提交中唯一的 8080 分。

写出没有限制时的转移方程:
fi=minjfj1+K+S×(Pj,iQj,i)f_i=\min_{j} f_{j-1}+K+S\times (P_{j,i}-Q_{j,i})
Pj,iP_{j,i} 是该段中所有数的最大值,Qj,iQ_{j,i} 是该段中所有数的最小值。
对于一条限制 (x,y)(x,y),假设 x<yx<y,则对于 iyi\ge y,其枚举的决策点 jj 需要满足 j>xj>x
stist_iii 对应的最小决策点 jj,对于 (x,y)(x,y),执行 stymax(sty,x+1)st_y\leftarrow \max(st_y,x+1),最后做一遍前缀最大值就能求出。
考虑分治,分治结构如下:
  • 设当前处理区间为 [l,r][l,r],取 mid=l+r2mid=\lfloor\frac{l+r}{2}\rfloor
  • 递归处理 [l,mid][l,mid]
  • 处理决策点在 [l,mid][l,mid] 时对 [mid+1,r][mid+1,r] 的贡献。
  • 递归处理 [mid+1,r][mid+1,r]
Pj.iQj,iP_{j.i}-Q_{j,i} 比较难处理,因为 j[l,mid],i[mid+1,r]j\in[l,mid],i\in[mid+1,r],考虑分讨,分讨最大值和最小值的下标分别在 midmid 的左侧还是右侧,一共有四种情况,这样就能把 [l,mid][l,mid][mid+1,r][mid+1,r] 独立开来,然后用线段树维护一下就行了,具体见代码,比较好理解。
时间复杂度 O(nlog2n)O(n\log^2 n)
CPP
#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 102510
#define int long long

int n,m,vk,vs,a[N],st[N],f[N];
int ln[N],lx[N],rn[N],rx[N],ar[N];

struct segt{
    #define mid ((l+r)>>1)

    int mn[N<<2];

    inline void un(int k){
        mn[k]=min(mn[k*2],mn[k*2+1]);
    }

    inline void build(int k,int l,int r){
        if(l==r){
            mn[k]=1e18;
            return;
        }
        build(k*2,l,mid);
        build(k*2+1,mid+1,r);

        un(k);
    }

    inline void upd(int k,int l,int r,int p,int d){
        if(l==r){
            mn[k]=d;
            return;
        }
        if(p<=mid){
            upd(k*2,l,mid,p,d);
        }
        else{
            upd(k*2+1,mid+1,r,p,d);
        }

        un(k);
    }

    inline int ask(int k,int l,int r,int L,int R){
        if(L>R){
            return 1e18;
        }
        if(L<=l&&R>=r){
            return mn[k];
        }
        int ans=1e18;

        if(L<=mid){
            ans=min(ans,ask(k*2,l,mid,L,R));
        }
        if(R>mid){
            ans=min(ans,ask(k*2+1,mid+1,r,L,R));
        }

        return ans;
    }

    #undef mid
}t;

inline void sol(int l,int r){
    if(l==r){
        f[l]=min(f[l],f[l-1]+vk);
        return;
    }

    int mid=(l+r)>>1;
    sol(l,mid);

    ln[mid+1]=1e9;
    lx[mid+1]=0;
    per(i,l,mid){
        ln[i]=min(a[i],ln[i+1]);
        lx[i]=max(a[i],lx[i+1]);
    }

    rn[mid]=1e9;
    rx[mid]=0;
    rep(i,mid+1,r){
        rn[i]=min(a[i],rn[i-1]);
        rx[i]=max(a[i],rx[i-1]);
    }

    //mx left mn left
    {
        t.build(1,l,mid);
        rep(i,l,mid){
            t.upd(1,l,mid,i,f[i-1]+vs*(lx[i]-ln[i]));
        }

        int j=mid;
        rep(i,mid+1,r){
            while(j>=l&&(ln[j]>rn[i]||lx[j]<rx[i])){
                j--;
            }
            if(j<l){
                break;
            }

            f[i]=min(f[i],t.ask(1,l,mid,st[i],j)+vk);
        }
    }

    //mx left mn right
    {
        t.build(1,l,mid);
        rep(i,l,mid){
            t.upd(1,l,mid,i,f[i-1]+vs*lx[i]);
        }

        int j=mid,k=mid+1;
        rep(i,mid+1,r){
            while(j>=l&&lx[j]<rx[i]){
                j--;
            }
            while(k-1>=l&&ln[k-1]>=rn[i]){
                k--;
            }
            if(j<l){
                break;
            }

            f[i]=min(f[i],t.ask(1,l,mid,max(st[i],k),j)-vs*rn[i]+vk);
        }
    }

    //mx right mn left
    {
        t.build(1,l,mid);
        rep(i,l,mid){
            t.upd(1,l,mid,i,f[i-1]-vs*ln[i]);
        }

        int j=mid,k=mid+1;
        rep(i,mid+1,r){
            while(j>=l&&ln[j]>rn[i]){
                j--;
            }
            while(k-1>=l&&lx[k-1]<=rx[i]){
                k--;
            }
            if(j<l){
                break;
            }

            f[i]=min(f[i],t.ask(1,l,mid,max(st[i],k),j)+vs*rx[i]+vk);
        }
    }

    //mx right mn right
    {
        ar[mid+1]=1e18;
        int j=mid+1;

        rep(i,mid+1,r){
            while(j-1>=l&&ln[j-1]>=rn[i]&&lx[j-1]<=rx[i]){
                j--;
                ar[j]=min(ar[j+1],f[j-1]);
            }

            if(st[i]<j){
                f[i]=min(f[i],ar[j]+vs*(rx[i]-rn[i])+vk);
            }
            else if(st[i]<=mid){
                f[i]=min(f[i],ar[st[i]]+vs*(rx[i]-rn[i])+vk);
            }
        }
    }

    sol(mid+1,r);
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n>>m>>vk>>vs;

    rep(i,1,n){
        cin>>a[i];
        st[i]=1;
        f[i]=1e18;
    }

    rep(i,1,m){
        int x,y;
        cin>>x>>y;

        if(x>y){
            swap(x,y);
        }
        st[y]=max(st[y],x+1);
    }

    rep(i,1,n){
        st[i]=max(st[i],st[i-1]);
    }

    sol(1,n);

    cout<<f[n]<<'\n';

    return 0;
}

评论

1 条评论,欢迎与作者交流。

正在加载评论...