Running In The Sky
格式难调,题面就不放了。
分析:
一句话题意:给定一张带点权的有向图,求最长点权路径及该路径上的最大点权。
很明显的$DAGDP$,因此需要缩点,将该图重建为一张$DAG$,在每个强联通分量中记录两个变量$sum,mx$表示该强联通分量中的点权和及最大点权。然后就是$DP$了,因为不仅要求最长点权路径,还要求路径上的最大点权,所以我们可以记录状态$f[x][0]$和$f[x][1]$分别表示以$x$为终点的路径中点权和最大的路径以及该路径上的最大点权。共有两个方程:
$egin{cases}f[y][0]=f[x][0],f[y][1]=f[x][1] & (f[x][0]>f[y][0])\f[y][1]=max(f[y][1],f[x][1]) & (f[x][0]==f[y][0]) end{cases}$
这样子这题就很好解决了。
Code:
//It is made by HolseLee on 26th Oct 2018 //Luogu.org P4742 #include<bits/stdc++.h> using namespace std; const int N=2e5+7, M=5e5+7; int n,m,val[N],ans0,ans1,h[N],head[N],cnte,dg[N],f[N][2]; int scc[N],mx[N],sum[N],idx,dfn[N],low[N],tot; bool ins[N]; struct Edge { int to,nxt; }edge[M],e[M]; queue<int>q; stack<int>t; inline int read() { char ch=getchar(); int x=0; bool flag=false; while( ch<'0' || ch>'9' ) { if( ch=='-' ) flag=true; ch=getchar(); } while( ch>='0' && ch<='9' ) { x=x*10+ch-'0'; ch=getchar(); } return flag ? -x : x; } inline void add_edge(int x,int y) { edge[++cnte].to=y; edge[cnte].nxt=h[x]; h[x]=cnte; } inline void add(int x,int y) { e[++cnte].to=y, e[cnte].nxt=head[x]; head[x]=cnte, dg[y]++; } void tarjan(int x) { dfn[x]=low[x]=++idx; ins[x]=1; t.push(x); int y; for(int i=h[x]; i; i=edge[i].nxt) { y=edge[i].to; if( !dfn[y] ) { tarjan(y); low[x]=min(low[x],low[y]); } else if( ins[y] ) { low[x]=min(low[x],dfn[y]); } } if( dfn[x]==low[x] ) { ++tot; do { y=t.top(); t.pop(); ins[y]=false; scc[y]=tot; sum[tot]+=val[y], mx[tot]=max(mx[tot],val[y]); } while( y!=x ); } } void rebuild() { cnte=0; for(int x=1; x<=n; ++x) for(int i=h[x],y; i; i=edge[i].nxt) { y=edge[i].to; if( scc[x]!=scc[y] ) add(scc[x],scc[y]); } } int main() { n=read(), m=read(); for(int i=1; i<=n; ++i) val[i]=read(); for(int i=1; i<=m; ++i) add_edge(read(), read()); for(int i=1; i<=n; ++i) if( !dfn[i] ) tarjan(i); rebuild(); for(int i=1; i<=tot; ++i) if( !dg[i] ) q.push(i); while( !q.empty() ) { int x=q.front(); q.pop(); f[x][0]+=sum[x]; f[x][1]=max(f[x][1],mx[x]); for(int i=head[x],y; i; i=e[i].nxt) { y=e[i].to; if( !(--dg[y]) ) q.push(y); if( f[x][0]>f[y][0] ) { f[y][0]=f[x][0], f[y][1]=f[x][1]; } else if( f[y][0]==f[x][0] ) { f[y][1]=max(f[y][1],f[x][1]); } } } for(int i=1; i<=tot; ++i) if( f[i][0]>ans0 ) { ans0=f[i][0], ans1=f[i][1]; } else if( f[i][0]==ans0 ) { ans1=max(ans1,f[i][1]); } printf("%d %d ",ans0,ans1); return 0; }