「CTSC2010」产品销售

「CTSC2010」产品销售

30pts的费用流都会吧...

100pts只要模拟费用流就行了,是不是很简单呀(

咕咕咕

(M_i)表示(i-1 o i)的正向边,(M_i^{'})表示反向边

(C_i)表示(i o i-1)的正向边,(C_i^{'})表示反向边

依次枚举(1,cdots,n)

当前枚举到(i),要使(i ightarrow t)满流

两种决策:(s ightarrow j o j+1 o cdots o i) or (i leftarrow i+1 leftarrow cdots leftarrow j leftarrow s)

下面表述中,起始位置就是(j)

第二种决策

由于是依次枚举,故(M_i+1,cdots,M_j)并没有流量,则费用为(sum_{k=i+1}^j cost[C_k])

由于(i)是顺次推过来,故可以直接对(sum_{k=1}^j cost[C_k])排序,跳过(kleq i || U[k]==0)的点,取最优即可。

第一种决策

对于当前决策,若有一条边(C_k( j+1leq k leq i))有流量,那么费用需要减去(cost[C_k]+cost[M_k])

可行流量为(min(w[C_k])(w[c_k] geq 1))

那么可以转化一下:在加入(k)这个点的时候,对于始于([1,k-1])的第一种决策的路径,若(C_k)有流量,那么全部减去(cost[C_k]),否则加上(cost[M_k])

(C_k)流量减为0时,对始于([1,k-1])的第一种决策的路径全部加上(cost[M_k]+cost[C_k])

显然对于(C_k)修改只会执行2次。


具体讲讲怎么维护吧...

线段树an1维护(w[C_x]),an2维护以(j)为起始到 当前枚举的点(i)的花费。

由于(an1)要维护(min(w[C_x])(w[C_x] geq1)),为了方便,初始值设为(inf)

第一种决策

an2查询([1,i])的最小值(Min),并找到其位置(k)

an1查询([k+1,i])(Minf)= (min(w[C_x])(w[C_x] geq1)) ,并找到其位置。

可行的流量(flow)(min(U[k],D[i],Minf))

将an1的([k+1,i])全部减去flow,(U[k]-=flow,D[i]-=flow)

对于an1中(w[C_k]==0)的点,权值设置为(inf),并对an2中([1,cdots ,k-1])的点加上(cost[M_k]+cost[C_k])

(U[k]==0),在an2中设置(k)权值为(inf)

第二种决策

起始位置为(k),可行流量为(flow=min(U[k],D[i]))

首先要将an1([i+1,k])当中权值为(inf)的点修改为0,用并查集跳过不是(inf)的点即可。

然后将an1([i+1,k])权值加(flow)(U[k]-=flow,D[i]-=flow)

枚举到下一个点i+1

(i+1)加入an2中(若(U[i+1]==0)设为(inf)

在an2中,([1,i])加上(w[C_{i+1}] geq 1?-cost[C_{i+1}]:cost[M_{i+1}])


其实可以发现an1,an2支持的操作是一样的

#include <bits/stdc++.h>
//#pragma GCC target("avx,avx2,sse4.2")
#define rep(q, a, b) for (int q = a, q##_end_ = b; q <= q##_end_; ++q)
#define dep(q, a, b) for (int q = a, q##_end_ = b; q >= q##_end_; --q)
#define mem(a, b) memset(a, b, sizeof a)
#define debug(a) cerr << #a << ' ' << a << "___" << endl
using namespace std;
// char buf[10000000], *p1 = buf, *p2 = buf;
#define Getchar() 
    getchar()  // p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 10000000, stdin), p1 == p2) ? EOF : *p1++
void in(int &r) {
    static char c;
    r = 0;
    bool flag(0);
    while (c = Getchar(), c < 48) (c == '-') && (flag = 1);
    do
        r = (r << 1) + (r << 3) + (c ^ 48);
    while (c = Getchar(), c > 47);
    flag && (r = -r);
}

const int mn = 100005;
const int INF = 2e9;
int n, D[mn], U[mn], P[mn], M[mn], C[mn];
struct node {
    int x, v;
    bool operator<(const node &A) const { return v < A.v; }
} an1[mn];
struct segment_tree {
    int at[mn << 2], addv[mn << 2], y_1, y_2, ad_v, minv[mn << 2];
    void build(int o, int l, int r, int v) {
        minv[o] = v, at[o] = l;
        if (l == r)
            return;
        int mid = l + r >> 1;
        build(o << 1, l, mid, v);
        build(o << 1 | 1, mid + 1, r, v);
    }
    void maintain(int o) {
        if (minv[o << 1] + addv[o << 1] < minv[o << 1 | 1] + addv[o << 1 | 1]) {
            minv[o] = minv[o << 1] + addv[o << 1];
            at[o] = at[o << 1];
        } else {
            minv[o] = minv[o << 1 | 1] + addv[o << 1 | 1];
            at[o] = at[o << 1 | 1];
        }
    }
    void change(int o, int l, int r, int adv) {
        adv += addv[o];
        if (l == r)
            minv[o] = ad_v - adv;
        else {
            int mid = l + r >> 1;
            if (y_1 <= mid)
                change(o << 1, l, mid, adv);
            else
                change(o << 1 | 1, mid + 1, r, adv);
            maintain(o);
        }
    }
    void change(int x, int v) {
        y_1 = x, ad_v = v;
        change(1, 1, n, 0);
    }
    void modify(int o, int l, int r) {
        if (y_1 <= l && r <= y_2)
            addv[o] += ad_v;
        else {
            int mid = l + r >> 1;
            if (y_1 <= mid)
                modify(o << 1, l, mid);
            if (y_2 > mid)
                modify(o << 1 | 1, mid + 1, r);
            maintain(o);
        }
    }
    void add(int l, int r, int v) {
        if (l > r)
            return;
        y_1 = l, y_2 = r, ad_v = v;
        modify(1, 1, n);
    }

    int Min, At;
    void ask(int o, int l, int r, int adv) {
        adv += addv[o];
        if (y_1 <= l && r <= y_2) {
            if (minv[o] + adv < Min)
                Min = minv[o] + adv, At = at[o];
            return;
        }
        int mid = l + r >> 1;
        if (y_1 <= mid)
            ask(o << 1, l, mid, adv);
        if (y_2 > mid)
            ask(o << 1 | 1, mid + 1, r, adv);
    }
    int ask(int l, int r) {
        if (l > r)
            return INF;
        y_1 = l, y_2 = r, Min = INF;
        ask(1, 1, n, 0);
        return Min;
    }
} an[2];
int fa[mn];
int find(int x) { return !fa[x] ? x : fa[x] = find(fa[x]); }
signed main() {
    freopen("product.in", "r", stdin);
    freopen("product.out", "w", stdout);
    in(n);
    rep(q, 1, n) in(D[q]);
    rep(q, 1, n) in(U[q]);
    rep(q, 1, n) in(P[q]);
    rep(q, 2, n) in(M[q]);
    rep(q, 2, n) in(C[q]);
    int sm = 0;
    rep(q, 2, n) sm += C[q], an1[q] = { q, sm + P[q] };
    sort(an1 + 2, an1 + n + 1);
    int tp = 2;
    an[0].build(1, 1, n, INF);
    an[1].build(1, 1, n, 0);
    long long ans = 0;
    sm = 0;
    rep(q, 1, n) {
        an[1].add(1, q - 1, an[0].ask(q, q) > 1e9 ? M[q] : -C[q]);
        sm += C[q];
        an[1].change(q, U[q] ? P[q] : INF);
        while (D[q]) {
            while (tp <= n && (an1[tp].x <= q || !U[an1[tp].x])) ++tp;
            if (tp > n || an[1].ask(1, q) <= an1[tp].v - sm) {
                int v = an[1].ask(1, q);
                int at = an[1].At, vl = an[0].ask(at + 1, q);
                int lim = min(min(D[q], U[at]), vl);
                ans += 1LL * lim * v;
                while (vl == lim) {
                    int at1 = an[0].At;
                    an[1].add(1, at1 - 1, C[at1] + M[at1]);
                    an[0].change(at1, INF);
                    vl = an[0].ask(at + 1, q);
                }
                an[0].add(at + 1, q, -lim);
                D[q] -= lim, U[at] -= lim;
                if (!U[at])
                    an[1].change(at, INF);
            } else {
                int at = an1[tp].x;
                int mid = at, lim = min(U[at], D[q]);
                U[at] -= lim, D[q] -= lim;
                while (find(mid) >= q + 1) {
                    an[0].change(find(mid), 0);
                    fa[find(mid)] = find(mid) - 1;
                }
                an[0].add(q + 1, at, lim);
                ans += 1LL * lim * (an1[tp].v - sm);
            }
        }
    }
    printf("%lld
", ans);
    return 0;
}
原文地址:https://www.cnblogs.com/klauralee/p/11358663.html