传送门:Annual Parade
题解
求链覆盖所有点的最小花费,考虑拆点跑最小费用最大流。
1
0
5
10^5
105次关于
C
C
C的询问说明费用流实际上和
C
C
C的关系不大。
先考虑如何抛开
C
C
C回答单次询问。
考虑拆点:将
i
i
i拆成
i
,
i
′
i,i'
i,i′。
源点
S
S
S->
i
i
i连一条流量为
1
1
1,费用为
0
0
0的边。
i
i
i->汇点
T
T
T连一条流量为
1
1
1,费用为
0
0
0的边。
每条路径
(
x
,
y
,
v
)
(x,y,v)
(x,y,v)连一条
x
−
>
y
′
x->y'
x−>y′流量为
1
1
1,费用为
v
v
v的边。
i
′
i'
i′->
i
i
i连一条流量为
+
∞
+\infty
+∞,费用为
0
0
0的边(多次经过一个点)。
观察每次一条新的增广路(费用为 c o s t cost cost)的贡献:连接了两条不连通的路径,使得原花费 − C -C −C;连成了环,也使得原花费 − C -C −C。
初始化费用为 n × C n\times C n×C(没有路径),每一条新的增广路的贡献为 c o s t − c cost-c cost−c。那么花费最小的方案就是选择所有 c o s t < c cost<c cost<c的增广路。
所以先 F l o y d Floyd Floyd跑一遍任意两点之间最短路,跑一遍最小费用最大流,依次记录每条增广路的花费。最后每次询问二分回答即可。
代码
#include<bits/stdc++.h>
using namespace std;
const int N=510,M=4e5+10;
const int inf=0x3f3f3f3f;
int n,m,K,S,T,f[255][255],vs[N],tim,lim;
int head[N],cur[N],to[M],nxt[M],w[M],c[M],tot=1;
bool inq[N];int dis[N],prf,prc,flw[N],cst[N];
vector<int>dg;
inline void lk(int u,int v,int vv,int cc)
{
to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=vv;c[tot]=cc;
to[++tot]=u;nxt[tot]=head[v];head[v]=tot;w[tot]=0;c[tot]=-cc;
}
char cp,OS[100];
inline void rd(int &x)
{
cp=getchar();x=0;
for(;!isdigit(cp);cp=getchar());
for(;isdigit(cp);cp=getchar()) x=(x<<3)+(x<<1)+(cp^48);
}
inline void ot(int x)
{
int re=0;
for(;(!re)||(x);x/=10) OS[++re]='0'+x%10;
for(;re;--re) putchar(OS[re]);
putchar('\n');
}
deque<int>que;
inline bool spfa()
{
int i,j,x;
memset(dis,0x3f,lim);dis[T]=0;inq[T]=true;que.push_back(T);
for(;que.size();){
x=que.front();que.pop_front();
for(i=head[x];i;i=nxt[i]){
j=to[i];if((!w[i^1])||(dis[j]<=dis[x]-c[i])) continue;
dis[j]=dis[x]-c[i];if(inq[j]) continue;
if(que.empty() || dis[j]<=dis[que.front()]) que.push_front(j);
else que.push_back(j);inq[j]=true;
}
inq[x]=false;
}
return dis[S]<inf;
}
int dfs(int x,int f,int cot)
{
vs[x]=tim;
if(x==T){
dg.push_back(cot);
int sz=dg.size();
prf+=f;flw[sz]=prf;
prc+=f*cot;cst[sz]=prc;
return f;
}
int j,res,ss=0;
for(int &i=cur[x];i;i=nxt[i]){
j=to[i];if((!w[i])||(vs[j]==tim)||(dis[j]!=dis[x]-c[i])) continue;
res=dfs(j,min(f-ss,w[i]),cot+c[i]);if(!res) continue;
w[i]-=res;w[i^1]+=res;ss+=res;
if(ss==f) return ss;
}
if(!ss) dis[x]=-1;
return ss;
}
int main(){
int i,j,k,x,y,z;
memset(f,0x3f,sizeof(f));
rd(n);rd(m);rd(K);
for(i=1;i<=n;++i) f[i][i]=0;
for(i=1;i<=m;++i){
rd(x);rd(y);rd(z);
f[x][y]=min(f[x][y],z);
}
for(k=1;k<=n;++k)
for(i=1;i<=n;++i)
for(j=1;j<=n;++j)
f[i][j]=min(f[i][j],f[i][k]+f[k][j]);
S=(n<<1)+1;T=S+1;lim=sizeof(int)*(T+2);
for(i=1;i<=n;++i) lk(S,i,1,0),lk(i+n,T,1,0);
for(i=1;i<=n;++i)
for(j=1;j<=n;++j) if((i!=j)&&(f[i][j]<inf))
lk(i,j+n,1,f[i][j]);
for(;spfa();){
for(vs[T]=tim;vs[T]==tim;){
tim++;memcpy(cur,head,lim);dfs(S,inf,0);
}
}
for(;K;--K){
rd(z);x=lower_bound(dg.begin(),dg.end(),z)-dg.begin();
ot((n-flw[x])*z+cst[x]);
}
return 0;
}