题解 P4742 【[Wind Festival]Running In The Sky】
P4742 [Wind Festival]Running In The Sky
题目大意:
给一张有向图,求一条点权最大的路径,和这条路径上的最大点权。
solution:
我们考虑将原图缩点,然后在新的 \(\text{DAG}\) 上拓扑排序进行 \(\text{DP}\) 。
我们设两个状态: \(f1[\,i\,]\) 、 \(f2[\,i\,]\) 分别表示走到 \(i\) 的最大路径和与最大点权,思考一下如何转移:
设从 \(x\) 走到 \(y\) ,每个强连通分量的点权和为 \(val[\,i\,]\) ,最大点权为 \(mx[\,i\,]\) 。
- 如果:\(f1[\,y\,]<f1[\,x\,]+val[\,y\,]\),则有:
\[f1[\,y\,]=f1[\,x\,]+val[\,y\,],f2[\,y\,]= \max \{f2[\,x\,],mx[\,y\,]\}
\]
- 如果:\(f1[\,y\,]==f1[\,x\,]+val[\,y\,]\),则有:
\[f2[\,y\,]=\max\{f2[\,x\,],f2[\,y\,]\}
\]
考虑答案统计:
\(ans1\) 、 \(ans2\) 与 \(f1\) 、\(f2\) 同义;
- 若 \(ans1<f1[\,x\,]\) ,则有:
\[ans1=f1[\,x\,],ans2=f2[\,x\,]
\]
- 若 \(ans1==f1[\,x\,]\) ,则有:
\[ans2= \max\{ans2,f2[\,x\,]\}
\]
细节处理:
- 缩点后最好新开一个邻接表,避免[SNOI2017]炸弹的杯具。
代码
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N=2e5+5,M=5e5+5;
int hd[N],nt[M],fr[M],to[M],cnt;
inline void tian(int x,int y){
to[++cnt]=y,fr[cnt]=x,nt[cnt]=hd[x],hd[x]=cnt;
}
int dfn[N],low[N],val[N],mx[N],of[N],chuo,scc;
int st[N],top; bool vis[N];
int a[N];
void dfs(int x){//模板
dfn[x]=low[x]=++chuo;
st[++top]=x,vis[x]=1;
for(int i=hd[x];i;i=nt[i]){
int y=to[i];
if(!dfn[y]){
dfs(y);
low[x]=min(low[x],low[y]);
}
else if(vis[y]) low[x]=min(low[x],dfn[y]);
}
if(dfn[x]==low[x]){
scc++;
while(1){
int y=st[top--];
val[scc]+=a[y],
mx[scc]=max(mx[scc],a[y]);
of[y]=scc,vis[y]=0;
if(x==y) break;
}
}
}
int nhd[N],nnt[M],nto[M],ncnt,du[N];
inline void ntian(int x,int y){
nto[++ncnt]=y,nnt[ncnt]=nhd[x],nhd[x]=ncnt;
du[y]++;
}
inline void suo(){
for(int i=1;i<=cnt;i++){
int x=of[fr[i]],y=of[to[i]];
if(x!=y) ntian(x,y);
}
}
int f1[N],f2[N];
int ans1,ans2;
queue<int> q;
inline void topo(){
for(int i=1;i<=scc;i++){
f1[i]=val[i],f2[i]=mx[i];
if(!du[i]) q.push(i);
}
while(q.size()){
int x=q.front();q.pop();
if(f1[x]>ans1) ans1=f1[x],ans2=f2[x];
else if(f1[x]==ans1) ans2=max(ans2,f2[x]);
for(int i=nhd[x];i;i=nnt[i]){
int y=nto[i];
if(f1[y]<f1[x]+val[y]){
f1[y]=f1[x]+val[y];
f2[y]=max(f2[x],mx[y]);
}
else if(f1[y]==f1[x]+val[y])
f2[y]=max(f2[x],f2[y]);
if(--du[y]==0) q.push(y);
}
}
}
int main(){
int n,m; scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1,x,y;i<=m;i++){
scanf("%d%d",&x,&y);
tian(x,y);//连边
}
for(int i=1;i<=n;i++)
if(!dfn[i]) dfs(i);//tarjin
suo();//缩点
topo();//拓扑排序+DP
printf("%d %d",ans1,ans2);
return 0;
}

浙公网安备 33010602011771号