• 「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;
    }
    
  • 相关阅读:
    [git 学习篇] git commit原理 --实践体会
    [git 学习篇]工作区和暂存区
    [git 学习篇] git文件版本回退再学习
    [git 学习篇]版本回退
    [git 学习篇] 修改文件
    [git 学习篇] 提交文件
    [git 学习篇] --创建git创库
    [测试框架学习] 测试框架的结构包含
    [python测试框架] http接口测试框架
    向SharePoint页面添加后台代码
  • 原文地址:https://www.cnblogs.com/klauralee/p/11358663.html
Copyright © 2020-2023  润新知