BZOJ 1920 Luogu P4217 [CTSC2010] product sales (cost flow simulation, tree line)

Topic Link

(bzoj) https://www.lydsy.com/JudgeOnline/problem.php?id=1920
(luogu) https://www.luogu.org/problem/P4217

answer

Cost Flow simulation.
First, such a construction may FIG following:
For each day \ (I \) to build a point, another new source and sink \ (S, T \) .

(. 1) \ (S \) to \ (I \) connected \ ((D_i, 0) \) (represented by line)

(2) \ (i \) to \ (i + 1 \) Even \ ((+ \ INF, C_i) \) (delay orders)

(3) \ (i + 1 \) to \ (i \) Even \ ((+ \ INF, M_i) \) (equivalent to delays in product orders in advance)

(. 4) \ (I \) to \ (T \) connected \ ((U_i, P_i) \) (produced product)
seeking the minimum cost maximum flow (i.e. seeking a minimum in the case of side full flow with a source connected to cost).

Consider how the simulation:
two important properties cost flow - edge of the point source will not be connected back flow; if not each selected from a short circuit augmented global optimum, but in any order and each source enumerator side were augmented point must be connected to the stream, the answer is right.
In view of the cost of construction of the stream, we give (each lateral edge \ (i \) and \ (i 1 \) + side between) the establishment of the reverse side, the right side is the opposite of the forward edge weights.
Suppose \ (a, b \) are side \ (i \ rightarrow i + 1 , i + 1 \ rightarrow i \) of the edge weights, if \ (i \ rightarrow i + 1 \) is the flow rate is not \ (0 \) , then when the \ (i + 1 \) flows \ (i \) time to find shortest path will go that cost \ (- a \) side, while giving \ (i \ rightarrow i + 1 \) flow \ (- 1 \) , until the flow becomes \ (0 \) so far. \ (i + 1 \ rightarrow i \) side of empathy.
Here there is a very wonderful idea - from left to right augmented.
Enumeration from left to right and each point source is connected, respectively, attempt to gain wide left and right augmented, substituted monovalent smaller.
When augmented to the right, find the longest path starting point, and then calculate the remaining traffic flow for the current point and that point of the longest road to \ (T \) the minimum value of the remaining traffic.
If we augmented the right \ (x \) traffic, the road will lead to augmented each point increase in the reverse flow from right to left side \ (x \) .
When the left augmentation, because each cross side has a "threshold", a point at its left augmentation to the reverse side of the increased flow to the right initially, flow through is less than equal to a threshold which the edge weight is negative, greater than the threshold edge weight is positive (note this threshold is different capacity, more than the threshold value stream can flow past! here I was wrong several times), we consider a one-time augmented in ensuring the right of all Collage unchanged, therefore augmented flow remaining flow current point, that point to the longest path \ (T \) minimum the remaining three of the flow, and maximum current point on the road point threshold.
If we left the augmentation \ (x \) traffic, it will lead to a reduction of each side of the road augmented threshold \ (x \) , this time of an edge if the threshold becomes \ (0 \) , so you want to modify the threshold of this edge.
Finally, if a and augmented process \ (T \) points connected to the flow becomes \ (0 \) , but also to remove it.
So we want to maintain a support structure of the operation data (repeat specific maintenance method below).
The following analysis of complexity, from left to right augmented the beauty is that it can to ensure that a threshold has been an increase in the lateral edge of the left side of the augmented point when augmented the right spot when has been reduced, which spans \ ( 0 \)The number is often several times, the right side of change is often several times.
Augmented cause each connected to a source of the edge flow out, or one connected to the sink edge flow out, or a right lateral Collage change, so the total number of operations is linear.

Finally, consider how to use the data structure maintenance.
Open three tree line, maintenance costs were augmented left, right augmented flow of expenses and middle lateral edges.
The second segment tree trees, augmented right maintenance costs, since the right side of the right augmentation is unchanged, thus maintaining each point directly to the right-most point to the right of the left and right to support the delete ( instead \ (+ \ INF \) ), the minimum value of the query and its location.
The same is true of a segment tree maintenance each point to the leftmost point from right to left and right, support modify, delete, query and minimum position.
The third segment tree trees, maintaining the flow of each lateral edge. First, to support the range of plus query and minimum position, then the most difficult operations - all of the initial position is \ (0 \) , if at any time after became any position after the first increase and decrease \ (0 \ ) , then to quickly enumerate these locations when an event occurs, and the corresponding operations on a segment tree. I use this method is pushdown time if a minimum interval son \ (0 \) , then recursively son, until you find the leaf nodes, the leaf nodes of zero assigned to \ (+ \ inf \) and a segment of the trees, and a corresponding operation. But there is a difficult problem is how to distinguish between the initial value \ (0 \) and after the first increase after modification reduces becomes \ (0 \) ? I started using the mark if the value is not \ (0 \) regarded as modified, but this is wrong, because it is possible to modify the position after several marked changes back to the \ (0 \) . so I was alone recorded a new tag \ (f \)Indicating whether modified. If and only if \ (F \) is true and a value of \ (0 \) perform a corresponding operation.

Time complexity \ (O (n-\ log n-) \) .

(I guess my wording has trouble ...... QAQ)

Code

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<utility>
#include<cassert>
#define llong long long
#define pli pair<llong,int>
#define mkpr make_pair
using namespace std;
 
void read(int &x)
{
    int f=1;x=0;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    x*=f;
}
 
const int N = 1e5;
const llong INF = 10000000000000ll;
llong a[N+3],b[N+3],w1[N+3],w2[N+3],c[N+3];
llong dl[N+3],dr[N+3];
int n;
 
struct SegmentTree1
{
    struct SgTNode
    {
        llong tag; pli mini;
        SgTNode() {mini = mkpr(INF,0); tag = 0;}
    } sgt[(N<<2)+3];
    void update(pli &x,pli y) {if(y.first<x.first) x = y;}
    void pushdown(int u)
    {
        assert(u<(N<<2));
        llong tag = sgt[u].tag;
        if(tag)
        {
            sgt[u<<1].mini.first += tag; sgt[u<<1].tag += tag;
            sgt[u<<1|1].mini.first += tag; sgt[u<<1|1].tag += tag;
            sgt[u].tag = 0;
        }
    }
    void pushup(int u)
    {
        assert(u<(N<<2));
        sgt[u].mini = mkpr(INF,0);
        update(sgt[u].mini,sgt[u<<1].mini);
        update(sgt[u].mini,sgt[u<<1|1].mini);
    }
    void build(int u,int le,int ri,llong a[])
    {
        assert(u<(N<<2));
        if(le==ri) {sgt[u].mini = mkpr(a[le],le); return;}
        int mid = (le+ri)>>1;
        build(u<<1,le,mid,a);
        build(u<<1|1,mid+1,ri,a);
        pushup(u);
    }
    void addval(int u,int le,int ri,int lb,int rb,llong x)
    {
        assert(u<(N<<2));
        if(le>=lb && ri<=rb) {sgt[u].mini.first += x; sgt[u].tag += x; return;}
        pushdown(u);
        int mid = (le+ri)>>1;
        if(lb<=mid) addval(u<<1,le,mid,lb,rb,x);
        if(rb>mid) addval(u<<1|1,mid+1,ri,lb,rb,x);
        pushup(u);
    }
    pli querymin(int u,int le,int ri,int lb,int rb)
    {
        assert(u<(N<<2));
        if(le>=lb && ri<=rb) {return sgt[u].mini;}
        pushdown(u);
        int mid = (le+ri)>>1; pli ret = mkpr(INF,0);
        if(lb<=mid) update(ret,querymin(u<<1,le,mid,lb,rb));
        if(rb>mid) update(ret,querymin(u<<1|1,mid+1,ri,lb,rb));
        pushup(u);
        return ret;
    }
} sgt1,sgt2;
 
struct SegmentTree2
{
    struct SgTNode
    {
        pli mini; llong tag; bool f;
        SgTNode() {mini = mkpr(0,0); tag = 0ll;}
    } sgt[(N<<2)+3];
    void update(pli &x,pli y) {if(y.first<x.first) x = y;}
    void pushup(int u)
    {
        assert(u<(N<<2));
        sgt[u].mini = mkpr(INF,0);
        update(sgt[u].mini,sgt[u<<1].mini);
        update(sgt[u].mini,sgt[u<<1|1].mini);
    }
    void pushdown(int u,int le,int ri)
    {
        assert(u<(N<<2));
        llong tag = sgt[u].tag;
        if(sgt[u].f)
        {
            int mid = (le+ri)>>1;
            if(le!=ri)
            {
                sgt[u<<1].mini.first += tag; sgt[u<<1].tag += tag; sgt[u<<1].f = true;
                sgt[u<<1|1].mini.first += tag; sgt[u<<1|1].tag += tag; sgt[u<<1|1].f = true;
            }
            sgt[u].tag = 0;
            if(sgt[u].mini.first!=0) return;
            if(le==ri) {sgt1.addval(1,1,n,1,le,b[le]+a[le]); sgt[u].mini.first = INF; return;}
            if(sgt[u<<1].mini.first==0) {pushdown(u<<1,le,mid);}
            if(sgt[u<<1|1].mini.first==0) {pushdown(u<<1|1,mid+1,ri);}
            pushup(u);
        }
    }
    void addval(int u,int le,int ri,int lb,int rb,llong x)
    {
        assert(u<(N<<2));
        if(le>=lb && ri<=rb) {sgt[u].mini.first += x; sgt[u].tag += x; sgt[u].f = true; pushdown(u,le,ri); return;}
        pushdown(u,le,ri); int mid = (le+ri)>>1;
        if(lb<=mid) addval(u<<1,le,mid,lb,rb,x);
        if(rb>mid) addval(u<<1|1,mid+1,ri,lb,rb,x);
        pushup(u);
    }
    pli querymin(int u,int le,int ri,int lb,int rb)
    {
        assert(u<(N<<2));
        if(le>=lb && ri<=rb) {return sgt[u].mini;}
        pushdown(u,le,ri); int mid = (le+ri)>>1; pli ret = mkpr(INF,0);
        if(lb<=mid) update(ret,querymin(u<<1,le,mid,lb,rb));
        if(rb>mid) update(ret,querymin(u<<1|1,mid+1,ri,lb,rb));
        pushup(u);
        return ret;
    }
} sgt3;
 
int main()
{
    scanf("%d",&n);
    for(int i=1; i<=n; i++) scanf("%lld",&w1[i]);
    for(int i=1; i<=n; i++) scanf("%lld",&w2[i]);
    for(int i=1; i<=n; i++) scanf("%lld",&c[i]);
    for(int i=1; i<n; i++) scanf("%lld",&b[i]);
    for(int i=1; i<n; i++) scanf("%lld",&a[i]);
    dl[1] = 0; for(int i=2; i<=n; i++) dl[i] = dl[i-1]+a[i-1];
    dr[n] = 0; for(int i=n-1; i>=1; i--) dr[i] = dr[i+1]-a[i];
    for(int i=1; i<=n; i++) dl[i]=dl[i]+c[i],dr[i]=dr[i]+c[i];
    sgt1.build(1,1,n,dr);
    sgt2.build(1,1,n,dl);
    for(int i=1; i<=n; i++) dl[i]-=c[i],dr[i]-=c[i];
    llong ans = 0ll;
    for(int i=1; i<=n; i++)
    {
        while(w1[i]>0)
        {
            pli vl = mkpr(INF,0),vr = mkpr(INF,0);
            pli tmp = sgt1.querymin(1,1,n,1,i);
            vl = mkpr(tmp.first-dr[i],tmp.second);
            tmp = sgt2.querymin(1,1,n,i,n);
            vr = mkpr(tmp.first-dl[i],tmp.second);
            if(vl.first<vr.first)
            {
                llong flow = min(w1[i],w2[vl.second]);
                if(vl.second<i)
                {
                    tmp = sgt3.querymin(1,1,n,vl.second,i-1);
                    flow = min(flow,tmp.first);
                    sgt3.addval(1,1,n,vl.second,i-1,-flow);
                }
                ans += flow*vl.first;
                w1[i] -= flow;
                w2[vl.second] -= flow;
                if(w2[vl.second]==0)
                {
                    sgt1.addval(1,1,n,vl.second,vl.second,INF);
                    sgt2.addval(1,1,n,vl.second,vl.second,INF);
                }
            }
            else
            {
                llong flow = min(w1[i],w2[vr.second]);
                ans += flow*vr.first;
                if(i<vr.second)
                {
                    sgt3.addval(1,1,n,i,vr.second-1,flow);
                }
                w1[i] -= flow;
                w2[vr.second] -= flow;
                if(w2[vr.second]==0)
                {
                    sgt1.addval(1,1,n,vr.second,vr.second,INF);
                    sgt2.addval(1,1,n,vr.second,vr.second,INF);
                }
            }
        }
        if(sgt3.querymin(1,1,n,i,i).first==0)
        {
            sgt3.addval(1,1,n,i,i,INF);
            sgt1.addval(1,1,n,1,i,b[i]+a[i]);
        }
    }
    printf("%lld\n",ans);
    return 0;
}

Guess you like

Origin www.cnblogs.com/suncongbo/p/11374733.html
Recommended