点击看题意
前置知识: L P LP LP对偶费用流。
考虑这样一个费用流:每条边 u v uv uv的流量设为 f u v f_{uv} fuv,容量设为 c u v c_{uv} cuv,费用设为 w u v w_{uv} wuv。 b u b_u bu设为流出-流入。要求 m i n i m i z e ∑ f u v w u v {\rm minimize} \sum f_{uv}w_{uv} minimize∑fuvwuv。通常来讲,如果 b u > 0 b_u>0 bu>0则从源点 S S S补流过来,否则流向汇点 T T T,因此这是一个最小费用最大流问题(假设原图没有负环)。
经过 一番操作 ,可以发现对偶过后长这样:
m i n i m i z e ∑ u b u p u + ∑ u v c u v max ( 0 , p v − p u − w u v ) {\rm minimize}\sum_{u}b_up_u+\sum_{uv}c_{uv}\max(0,p_v-p_u-w_{uv}) minimizeu∑bupu+uv∑cuvmax(0,pv−pu−wuv)
注意,两者对应的答案互为相反数,因此提取答案时要取负。
通常来讲,后面的式子一般出现在含差分约束的式子中。而为了减少一条约束中变量的数量,我们通常需要转化为前缀和。
PS:建议 b u b_u bu不要像这篇博客一样写成流入-流出,否则后面推出来怪怪的。。。
首先根据贪心,一定是将一个商店里的 A A A个珠宝按重量从小到大排序,然后将每个商店中对应第 i i i大的珠宝放在一起,如果这样都不行的话就不合法。
进一步的,考虑设 x i , j x_{i,j} xi,j表示第 i i i个商店选的编号 ≤ j \le j ≤j的珠宝的数量(注意一定要把 i = 0 i=0 i=0的变量也建出来),那么对于一条限制 ( u , v , w ) (u,v,w) (u,v,w), ∀ i ∈ [ 1 , K v ] \forall i\in [1,K_v] ∀i∈[1,Kv],设 j j j是最小的满足 S u , j + w ≥ S v , i S_{u,j}+w\ge S_{v,i} Su,j+w≥Sv,i的数,则 x u , j − 1 ≤ x v , i − 1 x_{u,j-1}\le x_{v,i-1} xu,j−1≤xv,i−1。
现在写出问题对应的线性规划形式:
m i n i m i z e ∑ x i , j ( P i , j − P i , j + 1 ) s . t . x i , j − x i , j + 1 ≤ 0 x i , j + 1 − x i , j − C i , j + 1 ≤ 0 x u , k − x v , j ≤ 0 x i , K i − x i , 0 − A ≤ 0 x i , 0 − x i , K i + A ≤ 0 x i , 0 = x j , 0 x i , j ≥ 0 {\rm minimize} \sum x_{i,j}(P_{i,j}-P_{i,j+1})\\ s.t.\ \ \ x_{i,j}-x_{i,j+1}\le 0\\x_{i,j+1}-x_{i,j}-C_{i,j+1}\le 0\\ x_{u,k}-x_{v,j}\le 0\\ x_{i,K_i}-x_{i,0}-A\le 0\\ x_{i,0}-x_{i,K_i}+A\le 0\\ x_{i,0}=x_{j,0}\\ x_{i,j}\ge 0 minimize∑xi,j(Pi,j−Pi,j+1)s.t. xi,j−xi,j+1≤0xi,j+1−xi,j−Ci,j+1≤0xu,k−xv,j≤0xi,Ki−xi,0−A≤0xi,0−xi,Ki+A≤0xi,0=xj,0xi,j≥0
现在对于每条差分约束 x − y ≤ w x-y\le w x−y≤w,都连一条 ( y , x , ∞ , w ) (y,x,\infty,w) (y,x,∞,w)的边,然后根据 P i , j − P i , j + 1 P_{i,j}-P_{i,j+1} Pi,j−Pi,j+1的正负建立源汇点平衡流量,答案就是对应的最小费用最大流。
但是这样无法处理多组询问。注意到原图上存在 x i , j x_{i,j} xi,j到 x i , j − 1 x_{i,j-1} xi,j−1的容量为 ∞ \infty ∞,费用为 0 0 0的边,而 x i , j x_{i,j} xi,j的流出量为 P i , j − P i , j + 1 P_{i,j}-P_{i,j+1} Pi,j−Pi,j+1,因此考虑先在 x i , j x_{i,j} xi,j到 x i , j − 1 x_{i,j-1} xi,j−1这条边流大小为 P i , j P_{i,j} Pi,j的流量,然后连一条 ( x i , j − 1 , x i , j , P i , j , 0 ) (x_{i,j-1},x_{i,j},P_{i,j},0) (xi,j−1,xi,j,Pi,j,0)的边表示可以反悔,不难发现这样每条边都自动流量平衡了。这样我们将问题转化为了最小费用可行流,即不断找负环增广,直到代价 > 0 >0 >0。
现在,注意到整张图实际上只有 x i , K i x_{i,K_i} xi,Ki到 x i , 0 x_{i,0} xi,0这一条负边,因此这条边一定会被增广,这实际上就是从 x 0 , j x_{0,j} x0,j到 x i , K i x_{i,K_i} xi,Ki的最小回归代价减去 A A A(注意 j j j是任意的,这是 x i , 0 = x j , 0 x_{i,0}=x_{j,0} xi,0=xj,0建出来的边),所以如果将所有 x 0 , j x_{0,j} x0,j看成源点 S S S, x i , K i x_{i,K_i} xi,Ki看成汇点 T T T,答案就是从 S S S到 T T T不断增广,直到代价 > A >A >A时的答案。
注意到代价为 A A A的边其实是废边,所以这张图实际上和 A A A没关系了。又因为费用流具有凸性,因此二分即可。
怎么判无解?有解等价于差分约束有解,也就是说没有负环(这里指容量为 ∞ \infty ∞的边),而有负环的时候总流量一定为 ∞ \infty ∞。
大力冲费用流即可。大概要跑 ∑ P i , j \sum P_{i,j} ∑Pi,j次最短路。
#include
#define fi first
#define se second
#define inf 0x3f3f3f3f3f3f3f3f
#define int ll
#define ll long long
using namespace std;
const int N=114514;
const int M=114514;
int n,m,s,t,idx;
int head[M],nxt[M],to[M],cap[M],cost[M],tot=1;
queue<int>Q;
int dis[N],pre[N],vis[N];
void add(int u,int v,int w,int c){
tot++,to[tot]=v,nxt[tot]=head[u],head[u]=tot,cap[tot]=w,cost[tot]=c;
tot++,to[tot]=u,nxt[tot]=head[v],head[v]=tot,cap[tot]=0,cost[tot]=-c;
}
bool spfa(){
for(int i=1;i<=idx;i++)dis[i]=inf,vis[i]=0;
dis[s]=0;
Q.push(s);
vis[s]=1;
while(Q.size()) {
int u=Q.front();Q.pop();
vis[u]=0;
for(int k=head[u];k;k=nxt[k]){
int v=to[k];
if(cap[k]>0&&dis[u]+cost[k]<dis[v]) {
dis[v]=dis[u]+cost[k];
pre[v]=k;
if(!vis[v]) {
vis[v]=1;
Q.push(v);
}
}
}
}
return dis[t]!=inf;
}
int cnt;
ll f[N],sm1[N],sm2[N];
void EK(){
while(spfa()){
int now=t,flo=inf;
while(now!=s){
int k=pre[now];
flo=min(flo,cap[k]);
now=to[k^1];
}
f[++cnt]=dis[t],sm1[cnt]=sm1[cnt-1]+flo,sm2[cnt]=sm2[cnt-1]+flo*dis[t];
if(sm1[cnt]>inf)break;
now=t;
while(now!=s){
int k=pre[now];
cap[k]-=flo;
cap[k^1]+=flo;
now=to[k^1];
}
}
}
int sz[35],id[35][35];
struct node{
int s,p,c;
bool operator <(const node &r)const{
return s<r.s;
}
}a[35][35];
signed main(){
//freopen("data.in","r",stdin);
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n,s=++idx,t=++idx;
for(int i=1;i<=n;i++){
cin>>sz[i];
for(int j=1;j<=sz[i];j++)cin>>a[i][j].s>>a[i][j].p>>a[i][j].c;
sort(a[i]+1,a[i]+1+sz[i]);
for(int j=1;j<sz[i];j++)id[i][j]=++idx;
id[i][0]=s,id[i][sz[i]]=t;
for(int j=0;j<sz[i];j++){
add(id[i][j],id[i][j+1],inf,a[i][j+1].c);
add(id[i][j],id[i][j+1],a[i][j+1].p,0);
}
}
cin>>m;
for(int i=1;i<=m;i++){
int u,v,w;cin>>u>>v>>w;
int k=1;
for(int j=1;j<=sz[v];j++){
while(k<=sz[u]&&a[v][j].s>a[u][k].s+w)k++;
add(id[v][j-1],id[u][k-1],inf,0);
}
}
EK();
int _Q;
cin>>_Q;
while(_Q--){
int x;cin>>x;
if(x>f[cnt]){
cout<<-1<<"\n";
}
else{
int p=lower_bound(f+1,f+1+cnt,x)-f-1;
cout<<x*sm1[p]-sm2[p]<<"\n";
}
}
}