「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;
}