题解 P4742 【[Wind Festival]Running In The Sky】

XG_Zepto

2018-07-11 09:14:02

Solution

### 思路 既然可以“到达一支风筝多次”,也就是**可以走回头路**,那么我们可以直接 Tarjan 缩点,在新的 DAG 上以**拓扑排序**的方法 DP。 ### 代码 ~~比官方短了不少,凑合着看吧~~ 同时安利博客:[【Luogu Wind Festival!】解题报告](https://www.xgzepto.cn/post/luogu-wind-festival) ```cpp #include <bits/stdc++.h> #define maxn 500010 using namespace std; struct Edge{ int from,to,next; Edge(int a=0,int b=0,int c=0){ from=a,to=b,next=c; } }l[maxn]; struct new_Edge{ int to,next; new_Edge(int a=0,int b=0){ to=a,next=b; } }e[maxn]; int head[maxn],cnt,n,cnt_n,top,m,ind,dfn[maxn],low[maxn],in[maxn],pin[maxn]; int a[maxn],id[maxn],num,siz[maxn],new_head[maxn],sta[maxn],pma[maxn],vis[maxn]; int dp[maxn][2]; void Add(int x,int y){ l[++cnt]=Edge(x,y,head[x]); head[x]=cnt; } void new_Add(int x,int y){ e[++cnt_n]=new_Edge(y,new_head[x]); new_head[x]=cnt_n; } void dfs(int u){ low[u]=dfn[u]=++ind; in[u]=1,sta[++top]=u; for (int i=head[u];i;i=l[i].next){ int v=l[i].to; if (!dfn[v]) dfs(v),low[u]=min(low[u],low[v]); else if (in[v]) low[u]=min(low[u],low[v]); } if (low[u]==dfn[u]){ int j=-1;num++; while(j!=u){ j=sta[top--]; id[j]=num; siz[num]+=a[j]; in[j]=0; pma[num]=max(pma[num],a[j]); } } } void tsort(){ queue<int>q; for (int i=1;i<=n;i++) dp[i][0]=siz[i],dp[i][1]=pma[i]; //dp[i][0] 维护的是走到 i 的点权和,同时 dp[i][1] 维护路径上的点权最大值。 for (int i=1;i<=n;i++) if (!pin[i]) q.push(i); while(!q.empty()){ int hq=q.front();q.pop(); for (int i=new_head[hq];i;i=e[i].next){ int v=e[i].to; if (dp[hq][0]+siz[v]>dp[v][0]){ dp[v][0]=dp[hq][0]+siz[v]; dp[v][1]=max(dp[hq][1],pma[v]);//注意这句和下面更新方法的差异 } if (dp[hq][0]+siz[v]==dp[v][0]) dp[v][1]=max(dp[v][1],dp[hq][1]); pin[v]--;if (pin[v]<=0) q.push(v); } } } int main(){ ios::sync_with_stdio(false); cin>>n>>m; for (int i=1;i<=n;i++) cin>>a[i]; for (int i=1,t1,t2;i<=m;i++){ cin>>t1>>t2;Add(t1,t2); } for (int i=1;i<=n;i++) if (!dfn[i]) dfs(i); for (int i=1;i<=m;i++) if (id[l[i].from]!=id[l[i].to]){ new_Add(id[l[i].from],id[l[i].to]); pin[id[l[i].to]]++; } int res=1;tsort(); for (int i=2;i<=num;i++) if (dp[i][0]>dp[res][0]||dp[i][0]==dp[res][0]&&dp[i][1]>=dp[res][1]) res=i; cout<<dp[res][0]<<" "<<dp[res][1]<<endl; return 0; } ```