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;
}
posted @ 2024-10-16 09:44  coding_goat_qwq  阅读(1)  评论(0编辑  收藏  举报