在第四个数据点中,通过搜索发现第1个点能达第470个点,第470个点有一条边直接通向第493个点。而前者的水晶价值9,后者的水晶价值32。
这是不是意味着可以从第470个点买入,第493个点卖出,这样就有23的收入?
但答案是8啊......是数据的问题还是我的问题(好像应该是后者
顺便贴一下我的缩点+拓扑的剧(ju)场(chang)版代码吧。没有注释,看着好玩就行)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<queue>
using namespace std;
const int N=6e5;
int n,m,num[2],head[2][N],val[N],visn,stan,dfsn[N],low[N],sta[N],sta_val[2][N],in[N],f[N],g[N],vis_min[N],ans;//f:当前持有 g:当前未持有
stack<int>s;
queue<int>q;
struct Edge{
int to;
int nxt;
}edge[2][N];
inline void add_edge(int x,int y,bool b){
edge[b][++num[b]].to=y;
edge[b][num[b]].nxt=head[b][x];
head[b][x]=num[b];
}
void Tarjan(int u){
dfsn[u]=low[u]=++visn;
s.push(u);
for(int i=head[0][u];i;i=edge[0][i].nxt){
int v=edge[0][i].to;
if(!dfsn[v]){
Tarjan(v);
low[u]=min(low[u],low[v]);
}
else if(!sta[v])//不要省略掉if内容!!!
low[u]=min(low[u],dfsn[v]);
}
if(dfsn[u]==low[u]){//单独成点或再次返回
sta[u]=++stan;
sta_val[0][stan]=sta_val[1][stan]=val[u];//买入&卖出
// if(val[u]==1)
// cout<<u<<':'<<val[u]<<endl;
cout<<u<<"->"<<stan<<' '<<val[u]<<endl;
while(s.top()!=u){
sta[s.top()]=stan;
sta_val[0][stan]=min(sta_val[0][stan],val[s.top()]);
sta_val[1][stan]=max(sta_val[1][stan],val[s.top()]);
// if(val[s.top()]==1)
// cout<<s.top()<<':'<<val[s.top()]<<endl;
// cout<<s.top()<<':'<<stan<<endl;
cout<<s.top()<<"->"<<stan<<' '<<val[s.top()]<<endl;
s.pop();
}
s.pop();
}
}
inline void read(int &x){
x=0;int f=1;char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')f=-1;
ch=getchar();
}
while(isdigit(ch)){
x=x*10+(ch^48);
ch=getchar();
}
x*=f;
}
int main(){
freopen("P1073_4.in","r",stdin);
// freopen("P1073_2.out","w",stdout);
read(n);read(m);
memset(f,-0x7f,sizeof f);
memset(g,-0x7f,sizeof g);
for(int i=1;i<=n;++i)
read(val[i]);
for(int i=1;i<=m;++i){
int x,y,z;
read(x);read(y);read(z);
// if((x==470&&y==493)||(y==470&&x==493&&2))return 0;
add_edge(x,y,false);
if(z==2)add_edge(y,x,false);
}
Tarjan(1);
for(int k=1;k<=n;++k)
for(int i=head[0][k];i;i=edge[0][i].nxt){
int j=edge[0][i].to;
if(sta[k]!=sta[j]){
add_edge(sta[k],sta[j],true);
++in[sta[j]];
}
}//以点为单位遍历边,建立新图
q.push(sta[1]);
f[sta[1]]=-sta_val[0][sta[1]];
g[sta[1]]=0;
for(int i=1;i<=stan;++i)
vis_min[i]=sta_val[0][i];
while(!q.empty()){
int u=q.front();q.pop();
for(int i=head[1][u];i;i=edge[1][i].nxt){
int v=edge[1][i].to;
// if(v==sta[470])return 0;
f[v]=max(f[v],max(f[u],g[u]-sta_val[0][v]));
g[v]=max(g[v],max(g[u],f[u]+sta_val[1][v]));
vis_min[v]=min(vis_min[v],vis_min[u]);
ans=max(ans,sta_val[1][v]-vis_min[v]);
if(!--in[v])q.push(v);
}
}
// printf("%d\n",max(f[sta[n]]+sta_val[1][sta[n]],g[sta[n]]));//该答案适用于可购买水晶任意次
printf("%d\n",ans);
cout<<val[470]<<' '<<val[493]<<endl;
// for(int i=1;i<=stan;++i)
// cout<<i<<":"<<sta_val[0][i]<<' '<<sta_val[1][i]<<' '<<vis_min[i]<<endl;
return 0;
}