P4742 【[Wind Festival]Running In The Sky】
阿新 • • 發佈:2020-09-19
相信來做這道題的人肯定都學過\(Tarjan\)縮點吧,如果沒有建議先去做P3387 【模板】縮點,如果你忘了,建議也去看看
滿足上面要求後,你會驚奇發現,這兩道題基本一樣,唯一的差別就是這道題需要記錄最大點權,比模板題多一個要求
但其實這很好想,在縮點的時候,我們另開一個數組記錄每一個縮點之後的最值,其餘部分完全一樣。至於程式我就不貼了
然後就是跑最大值,其實就是跑最長路,我們可以使用拓撲,記憶化搜尋或者DP,但是之前做的時候用的是拓撲,這裡就只說拓撲的做法
我們用\(dis\)表示到達該點時的最長路,\(maxn\)表示到達該點的最長路上的最大點權
在拓撲跑最長路的過程中,每更新一次最長路,就意味著這條最長路發生了改變,所以這個時候我們應當把\(maxn\)
#include <bits/stdc++.h> using namespace std; int n,m,ti,cnt,top,tot,ans=-99999999,sum,a[5000010],q[5000010],in[5000010],dis[5000010],pre[5000010],poi[5000010]; int dfn[5000010],low[5000010],vis[5000010],num[5000010],fir[5000010],head[5000010],heads[5000010],maxn[5000010]; int x[5000010],y[5000010]; struct node { int to,net; } e[5000010],es[5000010]; void add(int u,int v) { e[++tot].to=v; e[tot].net=head[u]; head[u]=tot; } void adds(int u,int v) { es[++tot].to=v; es[tot].net=heads[u]; heads[u]=tot; } void tarjan(int x) { vis[x]=1; q[++top]=x; dfn[x]=low[x]=++ti; for(int i=head[x];i;i=e[i].net) { int v=e[i].to; if(!dfn[v]) { tarjan(v); low[x]=min(low[x],low[v]); } else { if(vis[v]) low[x]=min(low[x],dfn[v]); } } if(low[x]==dfn[x]) { ++cnt; while(q[top+1]!=x) { vis[q[top]]=0; fir[q[top]]=cnt; num[cnt]+=a[q[top]]; poi[cnt]=max(poi[cnt],a[q[top]]); //記錄縮完點之後的最大點權 top--; } } } inline void topo() { queue<int> q; for(register int i=1;i<=cnt;i++) { dis[i]=num[i]; maxn[i]=poi[i]; if(!in[i]) q.push(i); } //記得初始化 while(!q.empty()) { int xx=q.front(); q.pop(); for(register int i=heads[xx];i;i=es[i].net) { int v=es[i].to; if(dis[xx]+num[v]>dis[v]) { //更新最大邊權之和 maxn[v]=0; //記得清空,因為更換了路徑 maxn[v]=max(poi[v],maxn[xx]); dis[v]=dis[xx]+num[v]; }else if(dis[xx]+num[v]==dis[v]){ maxn[v]=max(maxn[v],maxn[xx]); }//注意判斷邊權相同的情況,此時點權可能更大 if(--in[v]==0) q.push(v); } } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=m;i++) { scanf("%d%d",&x[i],&y[i]); add(x[i],y[i]); } for(int i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } tot=0; for(int i=1;i<=m;i++) { if(fir[x[i]]!=fir[y[i]]){ adds(fir[x[i]],fir[y[i]]); ++in[fir[y[i]]]; } } topo(); for(int i=1;i<=cnt;i++) { if(ans<dis[i]) { ans=dis[i]; sum=0; //這個地方我最開始一直沒考慮到(但是邊權我卻改了),95分調了很久 sum=max(sum,maxn[i]); }else if(ans==dis[i]){ ans=dis[i]; sum=max(sum,maxn[i]); }//和上面topo一樣的思路 } printf("%d %d",ans,sum); return 0; }