[ABC214H] Collecting(Primal-Dual 原始对偶算法)
分析
前置知识:Primal-Dual 原始对偶算法
或许还有不需要前置知识的做法?但是我不会
首先考虑 Tarjan 缩点,然后转化成一个 DAG。
每个点只能被收集一次,故考虑网络流,套路性地将
建边(以下令
,表示 个人从 出发。 ,表示这个点的权值只能取一次。 ,表示这个点可以被经过多次。 ,表示这条边可以被经过多次。 ,表示任何点都可以成为终点。
将原边权取反跑最小费用流。时间复杂度
最短路算法复杂度已经足够大了,我们需要使用 Primal-Dual 算法。但是原图的边权是负数,初始化也需要
暴力建图的思想是考虑流一条边加的贡献,由于原图是个 DAG,因此如果走了一条边,那么一定会有一些点之后不会再被遍历到,这些点实际上是拓扑序上位于该边起点和终点之间的点。
考虑每流一条边会失去哪些贡献,建图(用
,表示拓扑序在 之前的点不能被取。 ,表示第一次到这个点不会失去贡献。 ,表示多次到这个点不能再取一遍,会失去 的贡献。 ,表示走这条边拓扑序上位于起点终点之间的点不会再被走。 ,表示以这个点结束那么拓扑序在其之后的所有点不能被取。
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<map>
#include<unordered_map>
#include<vector>
#include<queue>
#include<bitset>
#include<set>
#include<ctime>
#include<random>
#include<cassert>
#define x1 xx1
#define y1 yy1
#define IOS ios::sync_with_stdio(false)
#define ITIE cin.tie(0);
#define OTIE cout.tie(0);
#define PY puts("Yes")
#define PN puts("No")
#define PW puts("-1")
#define P0 puts("0")
#define P__ puts("")
#define PU puts("--------------------")
#define popc __builtin_popcount
#define mp make_pair
#define fi first
#define se second
#define gc getchar
#define pc putchar
#define pb emplace_back
#define ALL(x) x.begin(),x.end()
#define rep(a,b,c) for(int a=(b);a<=(c);++a)
#define per(a,b,c) for(int a=(b);a>=(c);--a)
#define reprange(a,b,c,d) for(int a=(b);a<=(c);a+=(d))
#define perrange(a,b,c,d) for(int a=(b);a>=(c);a-=(d))
#define graph(i,j,k,l) for(int i=k[j];i;i=l[i].nxt)
#define lowbit(x) (x&-x)
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define mem(x,y) memset(x,y,sizeof x)
//#define double long double
#define int long long
//#define int __int128
using namespace std;
typedef long long i64;
using pii=pair<int,int>;
bool greating(int x,int y){return x>y;}
bool greatingll(long long x,long long y){return x>y;}
inline int rd(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}return x*f;
}
inline void write(int x,char ch='\0'){
if(x<0){x=-x;putchar('-');}
int y=0;char z[40];
while(x||!y){z[y++]=x%10+48;x/=10;}
while(y--)putchar(z[y]);if(ch!='\0')putchar(ch);
}
bool Mbg;
const int maxn=4e5+5,maxm=2e6+5,inf=0x3f3f3f3f;
const long long llinf=0x3f3f3f3f3f3f3f3f;
int n,m,k,b[maxn],c[maxn],s[maxn];
int u[maxn],v[maxn];
vector<int>G[maxn];
int dfn[maxn],low[maxn],dfncnt;
int sta[maxn],tp;
int scc[maxn],sc;
bool vis[maxn];
void tar(int x){
dfn[x]=low[x]=++dfncnt,vis[x]=1,sta[++tp]=x;
for(int u:G[x]){
if(!dfn[u])tar(u),low[x]=min(low[x],low[u]);
else if(vis[u])low[x]=min(low[x],dfn[u]);
}
if(low[x]==dfn[x]){
int y;++sc;
do{y=sta[tp--],scc[y]=sc,vis[y]=0;}while(x^y);
}
}
int S,T;
struct edge{
int to,nxt,w,c;
}a[maxm];
int head[maxn],edges;
void add(int x,int y,int z,int w){
a[++edges]=(edge){y,head[x],z,w};
head[x]=edges;
}
void add_edge(int x,int y,int z,int w){
add(x,y,z,w),add(y,x,0,-w);
}
int dis[maxn],dinic[maxn];
int h[maxn];
int pre[maxn],e[maxn];
bool dij(){
rep(i,1,T)dis[i]=dinic[i]=llinf,vis[i]=0;
priority_queue<pii,vector<pii>,greater<pii> >q;
dis[S]=0,q.push(mp(0,S));
while(!q.empty()){
pii nw=q.top();q.pop();
if(vis[nw.se])continue;vis[nw.se]=1;
graph(i,nw.se,head,a){
int u=a[i].to,exdis=a[i].c+h[nw.se]-h[u];
assert(!a[i].w||exdis>=0);
if(a[i].w&&dis[u]>nw.fi+exdis){
dis[u]=nw.fi+exdis,dinic[u]=min(dinic[nw.se],a[i].w),pre[u]=nw.se,e[u]=i;
q.push(mp(dis[u],u));
}
}
}
return vis[T];
}
int EK(){
int res=0,flow=0;
while(dij()){
flow+=dinic[T];
assert(h[S]==0);
res+=dinic[T]*(dis[T]+h[T]);
rep(i,1,T)h[i]+=dis[i];
int p=T;
while(p^S){
a[e[p]].w-=dinic[T],a[e[p]^1].w+=dinic[T];
p=pre[p];
}
}
return res;
}
void solve_the_problem(){
n=rd(),m=rd(),k=rd();
rep(i,1,m){
int x=rd(),y=rd();
u[i]=x,v[i]=y,G[x].emplace_back(y);
}
rep(i,1,n)b[i]=rd();
rep(i,1,n)if(!dfn[i])tar(i);
// rep(i,1,n)write(scc[i],32);P__;
rep(i,1,n)G[i].clear();
rep(i,1,n)c[scc[i]]+=b[i];
rep(i,1,m){
if(scc[u[i]]!=scc[v[i]]){
assert(scc[u[i]]>scc[v[i]]);
G[scc[u[i]]].emplace_back(scc[v[i]]);
}
}
per(i,sc,1)s[i]=s[i+1]+c[i];
S=2*sc+1,T=2*sc+2,edges=1;
add_edge(S,scc[1],k,s[scc[1]+1]);
rep(i,1,sc)add_edge(i,i+sc,1,0),add_edge(i,i+sc,k,c[i]),add_edge(i+sc,T,k,s[1]-s[i]);
rep(i,1,sc){
for(int u:G[i]){
add_edge(i+sc,u,k,s[u+1]-s[i]);
}
}
write(k*s[1]-EK());
}
bool Med;
signed main(){
// freopen(".in","r",stdin);freopen(".out","w",stdout);
// fprintf(stderr,"%.3lfMB\n",(&Mbg-&Med)/1048576.0);
int _=1;
while(_--)solve_the_problem();
}
/*
5 5 10
1 2
2 3
3 2
1 4
1 5
1 4 5 2 8
*/
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App