题解 P1073 【最优贸易】
why_always_china · · 题解
看到大家的题解都没有缩点DP的,我就乱写了一个。由于本人水平太渣,直接深搜,有点爆栈,只有90分,不过据说linux栈会略大一点,或许就可以水过了。所以本题解并不适合复制,仅供参考。
思路比较好想:强联通分量之间是拓扑的,再加上50%的数据没有环,这就暗示我们,可以缩点DP。我在这里采用了tarjan算法来求出强联通分量,分别记录最小和最大价格。然后缩点时,我不知道有什么好方法,就直接建了一个新图,然后DP,方程大体类似SPFA。
program trade;
const maxn=100001;
maxm=500001;
maxq=200000;
var h,h2,dfn,low,stack,naive,big,small,rd,new,money:array[1..maxn] of longint;
queue:array[1..200003] of longint;
visit,f:array[1..maxn] of boolean;
v,v2,next,nt:array[1..maxm] of longint;
n,p,hd,tl,i,s,t,deep,d,m,qs,z,num:longint;
function min(a,b:longint):longint;
begin
if a>b then exit(b) else exit(a);
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a) else exit(b);
end;
procedure print(x:longint);
begin
while stack[deep]<>x do
begin
new[stack[deep]]:=x;
big[x]:=max(big[x],naive[stack[deep]]);
small[x]:=min(small[x],naive[stack[deep]]);
f[stack[deep]]:=false;
dec(deep);
end;
new[stack[deep]]:=x;
big[x]:=max(big[x],naive[stack[deep]]);
small[x]:=min(small[x],naive[stack[deep]]);
f[stack[deep]]:=false;
dec(deep);
end;
procedure dfs(x:longint);
var i,qs:longint;
begin
inc(d);
dfn[x]:=d;
low[x]:=d;
inc(deep);
stack[deep]:=x;
f[x]:=true;
qs:=h[x];
while qs>0 do
begin
if not visit[v[qs]] then
begin
visit[v[qs]]:=true;
dfs(v[qs]);
low[x]:=min(low[x],low[v[qs]]);
end
else
if f[v[qs]] then low[x]:=min(low[x],dfn[v[qs]]);
qs:=next[qs];
end;
if dfn[x]=low[x] then print(x);
end;
begin
fillchar(visit,sizeof(visit),false);
fillchar(f,sizeof(f),false);
fillchar(h,sizeof(h),0);
fillchar(h2,sizeof(h2),0);
fillchar(new,sizeof(new),0);
fillchar(big,sizeof(big),0);
fillchar(small,sizeof(small),1);
fillchar(rd,sizeof(rd),0);
fillchar(money,sizeof(money),0);
read(n,m);
p:=0;
for i:=1 to n do read(naive[i]);
for i:=1 to m do
begin
read(s,t,z);
inc(p);
v[p]:=t;
next[p]:=h[s];
h[s]:=p;
if z=2 then
begin
inc(p);
v[p]:=s;
next[p]:=h[t];
h[t]:=p;
end;
end;
for i:=1 to n do if not visit[i] then
begin
visit[i]:=true;
dfs(i);
end;
p:=0;
for i:=1 to n do
begin
qs:=h[i];
while qs>0 do
begin
t:=v[qs];
if new[t]<>new[i] then
begin
inc(p);
inc(rd[new[t]]);
v2[p]:=new[t];
nt[p]:=h2[new[i]];
h2[new[i]]:=p;
end;
qs:=next[qs];
end;
end;
hd:=0;
tl:=0;
num:=0;
for i:=1 to n do if (rd[i]=0)and(i=new[i]) then
begin
tl:=tl mod maxq +1;
queue[tl]:=i;
inc(num);
end;
while num>0 do
begin
hd:=hd mod maxq+1;
qs:=h2[queue[hd]];
dec(num);
while qs>0 do
begin
t:=v2[qs];
dec(rd[t]);
small[t]:=min(small[t],small[queue[hd]]);
money[t]:=max(money[queue[hd]],big[t]-small[t]);
if rd[t]=0 then
begin
tl:=tl mod maxq +1;
queue[tl]:=t;
inc(num);
end;
qs:=nt[qs];
end;
end;
if (money[new[n]])>0 then
writeln(money[new[n]]) else writeln(0);
end.