题目:最优贸易
思路:
tarjan+dp。
要注意缩点后仍要判断每个点是否可达终点。
代码:
#include<bits/stdc++.h>
using namespace std;
#define maxn 100000
#define maxm 500000
#define read(x) scanf("%d",&x)
int n,m;
int w[maxn+5];
vector<int> a[maxn+5];
int pre[maxn+5]= {0},low[maxn+5],clk=0;
stack<int> s;
int cnt=0,isin[maxn+5];
vector<int> g[maxn+5];
int val[maxn+5]= {0},val2[maxn+5];
int vis[maxn+5]= {0};
bool canuse[maxn+5]= {0};
int isout;
void tarjan(int x) {
pre[x]=low[x]=++clk;
s.push(x);
for(int i=0; i<a[x].size(); i++) {
int y=a[x][i];
if(!pre[y]) {
tarjan(y);
low[x]=min(low[x],low[y]);
} else if(!isin[y]) {
low[x]=min(low[x],pre[y]);
}
}
if(pre[x]==low[x]) {
cnt++;
int u;
val2[cnt]=1e9;
do {
u=s.top();
s.pop();
if(u==n) isout=cnt;
isin[u]=cnt;
val[cnt]=max(w[u],val[cnt]);
val2[cnt]=min(w[u],val2[cnt]);
} while(u!=x);
}
}
void make_g() {
for(int i=1; i<=n; i++) {
for(int j=0; j<a[i].size(); j++) {
if(isin[i]!=isin[a[i][j]]) {
g[isin[i]].push_back(isin[a[i][j]]);
}
}
}
}
void dfs(int x) {
if(vis[x]||!canuse[x]) return ;
vis[x]=val[x];
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
dfs(y);
vis[x]=max(vis[x],vis[y]);
}
return ;
}
void readin() {
read(n),read(m);
for(int i=1; i<=n; i++) read(w[i]);
for(int i=1; i<=m; i++) {
int x,y,opr;
read(x),read(y),read(opr);
a[x].push_back(y);
if(opr==2) a[y].push_back(x);
}
}
bool find(int x) {
if(x==isout) return canuse[x]=true;
if(vis[x]) return canuse[x];
vis[x]=true;
for(int i=0; i<g[x].size(); i++) {
int y=g[x][i];
canuse[x]=max(find(y),canuse[x]);
}
return canuse[x];
}
int main() {
readin();
for(int i=1;i<=n;i++) if(!pre[i]) tarjan(i);
make_g();
for(int i=1;i<=cnt;i++) {
if(!vis[i]) find(i);
}
memset(vis,0,sizeof(vis));
for(int i=1; i<=cnt; i++) {
if(!vis[i]) dfs(i);
}
int ans=0;
for(int i=1; i<=cnt; i++) {
ans=max(ans,vis[i]-val2[i]);
}
printf("%d",ans);
return 0;
}