luogu P4217 [CTSC2010]產品銷售

luogu

題目給的東西可以搞成一個匹配模型,然後我們先把費用流的圖建出來

  • \(s->i\),流量\(d_i\),費用\(0\)
  • \(i->t\),流量\(u_i\),費用\(p_i\)
  • \(i->i+1\),流量\(\infty\),費用\(c_i\)
  • \(i+1->i\),流量\(\infty\),費用\(m_i\)

(相當於是每個訂單老鼠必須要找到對應的產品匹配)

然後考慮模擬費用流,如果我們從左至右枚舉\(d_i\)進行增廣,那麼顯然有兩種路徑,一種往左走,一種往右走,而往右走會產生一些反向弧,後面在反向弧右邊增廣到反向弧左邊時,一定會用到這個反向弧(因爲邊權爲負),同時往右走不會經過反向弧(因爲右邊還沒有增廣)

那麼我們用線段樹維護從當前點到每個點的費用,每次掃到下一個點的時候相當於把這個點連到後面的邊換個方向,這就是前綴/後綴加法;還有可能要把一些向左的邊臨時替換成反向弧,也可以線段樹區間修改;又因爲反向弧是有流量限制的,就多用一個線段樹維護每條反向弧剩餘容量.每次找到一個費用最小的點增廣,增廣流量爲源點出發的剩餘流量、從某點到匯點的剩餘流量、以及 如果向左走還有路上反向弧剩餘流量 的最小值,再維護一下這個流量流過去以後產生的情況,包括有些邊流滿,不能用了(把邊權設爲\(\infty\)),反向弧出現(可以差分維護每個邊上出現的反向弧容量,然後在掃到反向弧右端點後時加入向左反向弧貢獻),以及反向弧流滿了(去掉反向弧貢獻)

#include<bits/stdc++.h>
#define LL long long
#define uLL unsigned long long
#define db double

using namespace std;
const int N=1e5+10;
const LL inf=1ll<<50;
int rd()
{
    int x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
struct node
{
    LL x,p;
    bool operator < (const node &bb) const {return x<bb.x;}
}sht;
node minn(node aa,node bb){return aa<bb?aa:bb;}
struct smgttr
{
    node s[N<<2];
    LL tg[N<<2];
    void psup(int o){s[o]=minn(s[o<<1],s[o<<1|1]);} 
    void ad(int o,LL x){s[o].x+=x,tg[o]+=x;}
    void psdn(int o){if(tg[o]) ad(o<<1,tg[o]),ad(o<<1|1,tg[o]),tg[o]=0;}
    void modif(int o,int l,int r,int ll,int rr,LL x)
    {
        if(ll>rr) return;
        if(ll<=l&&r<=rr){ad(o,x);return;}
        psdn(o);
        int mid=(l+r)>>1;
        if(ll<=mid) modif(o<<1,l,mid,ll,rr,x);
        if(rr>mid) modif(o<<1|1,mid+1,r,ll,rr,x);
        psup(o);
    }
    node quer(int o,int l,int r,int ll,int rr)
    {
        if(ll>rr) return sht;
        if(ll<=l&&r<=rr) return s[o];
        psdn(o);
        node an=sht;
        int mid=(l+r)>>1;
        if(ll<=mid) an=minn(an,quer(o<<1,l,mid,ll,rr));
        if(rr>mid) an=minn(an,quer(o<<1|1,mid+1,r,ll,rr));
        psup(o);
        return an;
    }
}tr1,tr2;
int n,d[N],u[N],q[N],m[N],c[N];
LL ans,dd[N];
void bui(int o,int l,int r)
{
    if(l==r)
    {
        tr1.s[o]=(node){q[l],l};
        tr2.s[o]=(node){inf,l};
        return;
    }
    int mid=(l+r)>>1;
    bui(o<<1,l,mid),bui(o<<1|1,mid+1,r);
    tr1.psup(o),tr2.psup(o);
}

int main()
{
    sht.x=inf;
    n=rd();
    for(int i=1;i<=n;++i) d[i]=rd();
    for(int i=1;i<=n;++i) u[i]=rd();
    for(int i=1;i<=n;++i) q[i]=rd();
    for(int i=1;i<n;++i) m[i]=rd();
    for(int i=1;i<n;++i) c[i]=rd();
    bui(1,1,n);
    for(int i=1;i<n;++i)
        tr1.modif(1,1,n,i+1,n,c[i]);
    for(int i=1;i<=n;++i)
    {
        while(d[i])
        {
            node zl=tr1.quer(1,1,n,1,i-1),zr=tr1.quer(1,1,n,i,n);
            if(zl<zr)
            {
                int p=zl.p;
                node gz=tr2.quer(1,1,n,p,i-1);
                LL dt=min(1ll*min(d[i],u[p]),gz.x);
                ans+=zl.x*dt,d[i]-=dt,u[p]-=dt;
                if(!u[p]) tr1.modif(1,1,n,p,p,inf);
                if(gz.x)
                {
                    tr2.modif(1,1,n,p,i-1,-dt);
                    while(1)
                    {
                        gz=tr2.quer(1,1,n,p,i-1);
                        if(gz.x) break;
                        tr1.modif(1,1,n,1,gz.p,c[gz.p]+m[gz.p]),tr2.modif(1,1,n,gz.p,gz.p,inf);
                    }
                }
            }
            else
            {
                int p=zr.p;
                LL dt=min(d[i],u[p]);
                ans+=zr.x*dt,d[i]-=dt,u[p]-=dt;
                if(!u[p]) tr1.modif(1,1,n,p,p,inf);
                dd[i]+=dt,dd[p]-=dt;
            }
        }
        tr1.modif(1,1,n,i+1,n,-c[i]),tr1.modif(1,1,n,1,i,m[i]);
        dd[i]+=dd[i-1];
        if(dd[i])
            tr1.modif(1,1,n,1,i,-c[i]-m[i]),tr2.modif(1,1,n,i,i,-inf+dd[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章