题目链接:Antinomy与伊尔美格


比较明显的缩点,但是缩点之后怎么求最大值呢?

我们缩点变成DAG之后,因为求最大值,而且不能往回走,所以跑最长路即可。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5e5+10,M=1e6+10;
int n,m,xx[N],u,k,a[N],b[N],res,d[N];
int dfn[N],low[N],sum[N],col[N],co,cnt; bool vis[M],p[N],flag[N];
vector<int> v1[M],v2[M];	stack<int> st;
void Tarjan(int x){
	dfn[x]=low[x]=++cnt;	vis[x]=1;	st.push(x);
	for(int i=0;i<v1[x].size();i++){
		int to=v1[x][i];
		if(!dfn[to]){
			Tarjan(to);	low[x]=min(low[x],low[to]);
		}else if(vis[to]) low[x]=min(low[x],dfn[to]);
	}
	if(low[x]==dfn[x]){
		int u; co++;
		do{
			u=st.top();	st.pop(); vis[u]=0; sum[co]+=xx[u]; col[u]=co;
			flag[co]|=p[u];
		}while(u!=x);
	}
}
void spfa(){
	memset(d,0xcf,sizeof d); queue<int> q;	q.push(u); vis[u]=1; d[u]=0;
	while(q.size()){
		int u=q.front();	q.pop();	vis[u]=0;
		for(int i=0;i<v1[u].size();i++){
			int to=v1[u][i],w=v2[u][i];
			if(d[to]<d[u]+w){
				d[to]=d[u]+w;
				if(!vis[to])	vis[to]=1,q.push(to);
			}
		}
	}
}
signed main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++)	scanf("%d %d",&a[i],&b[i]),v1[a[i]].push_back(b[i]);
	for(int i=1;i<=n;i++)	scanf("%d",&xx[i]);
	cin>>u>>k;
	for(int i=1,x;i<=k;i++)	scanf("%d",&x),p[x]=1;
	for(int i=1;i<=n;i++)	if(!dfn[i])	Tarjan(i);
	for(int i=1;i<=n;i++)	v1[i].clear();
	for(int i=1;i<=co;i++)	v1[i].push_back(i+co),v2[i].push_back(sum[i]);
	for(int i=1;i<=m;i++){
		int u=col[a[i]],v=col[b[i]];
		if(u!=v)	v1[u+co].push_back(v),v2[u+co].push_back(0);
	} 
	u=col[u];
	spfa();
	for(int i=1;i<=co;i++)	if(flag[i])	res=max(res,d[i+co]);
	cout<<res<<endl;
	return 0;
}