P3627 [APIO2009] 抢掠计划 做题记录
如果抢劫了一个 SCC 上的点,那么就会把这个 SCC 上的 ATM 全抢完。所以我们先缩点,然后拓扑排序 dp 即可。
注意到只用从起点缩一次点即可,因为我们只用走到起点可达的点。时间复杂度 \(O(n+m)\)。
点击查看代码
int n,m;
int a[maxn],b[maxn];
int st,t,ed[maxn],ED[maxn],ST;
int val[maxn],totval[maxn];
int dfn[maxn],dfncnt,low[maxn];
bool vis[maxn];
int bel[maxn],belcnt;
int stk[maxn],top;
int deg[maxn],dp[maxn];
vector<int>G[maxn];
void dfs(int u) {
vis[u]=1;
stk[++top]=u;
dfn[u]=low[u]=++dfncnt;
for(auto v:G[u]) {
if(!dfn[v]) dfs(v),low[u]=min(low[u],low[v]);
else if(vis[v]) low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u]) {
belcnt++;
while(1) {
int v=stk[top--];
vis[v]=0;
bel[v]=belcnt;
if(u==v) break;
}
}
}
signed main() {
in2(n,m);
For(i,1,m) {
in2(a[i],b[i]);
G[a[i]].push_back(b[i]);
}
For(i,1,n) in1(val[i]);
in2(st,t);
For(i,1,t) in1(ed[i]);
dfs(st);
For(i,1,n) G[i].clear(),totval[bel[i]]+=val[i];
For(i,1,t) ED[bel[ed[i]]]=1;
ST=bel[st];
For(i,1,m) a[i]=bel[a[i]],b[i]=bel[b[i]];
For(i,1,m) if(a[i]!=b[i]&&a[i]&&b[i]) G[a[i]].push_back(b[i]),deg[b[i]]++;
queue<int>q;
q.push(ST); dp[ST]=totval[ST];
int ans=0;
while(!q.empty()) {
int u=q.front();q.pop();
if(u==0) continue;
for(auto v:G[u]) {
dp[v]=max(dp[v],dp[u]+totval[v]);
deg[v]--;
if(!deg[v]) q.push(v);
}
if(ED[u]) ans=max(ans,dp[u]);
}
cout<<ans;
}
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/18469038