1 solutions
-
0
难度: 蓝
算法: 强连通分量,缩点,拓扑排序
先跑强连通分量,缩点。记录缩完的点的点权,以及是否有酒吧。
进行拓扑排序 dp 。初始状态是起点为该点点权,其它全为负无穷。然后跑拓扑排序。注意拓扑排序是在所有入度为 的点开始的而不是起点。
最后统计所有有酒吧的点的最大值。
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll n,m,a,b,g,p,ans,f[500050],r[500050],pt[500050],w[500050],x[500050],y[500050]; //w[],x[]钱数 r[],y[]是否有酒吧 f[]答案 g起点 ll l[500050],d[500050],in[500050],s[500050],c,t; stack<ll> st; vector<ll> e[500050],k[500050]; queue<ll> tp; void tarj(ll u){ l[u]=d[u]=++c; st.push(u); in[u]=1; for(ll i=0;i<ll(e[u].size());i++){ ll v=e[u][i]; if(!d[v]){ tarj(v); l[u]=min(l[u],l[v]); } else if(in[v]) l[u]=min(l[u],d[v]); } if(l[u]==d[u]){ t++; while(1){ s[st.top()]=t; in[st.top()]=0; if(st.top()==u){ st.pop(); break; } st.pop(); } } } int main(){ ios::sync_with_stdio(0); cin>>n>>m; for(ll i=1;i<=m;i++){ cin>>a>>b; e[a].push_back(b); } for(ll i=1;i<=n;i++) cin>>w[i]; cin>>g>>p; for(ll i=1;i<=p;i++) cin>>a,r[a]=1; for(ll i=1;i<=n;i++){ if(!d[i]) tarj(i); } g=s[g]; for(ll i=1;i<=n;i++){ x[s[i]]+=w[i]; if(r[i]==1) y[s[i]]=1; } for(ll i=1;i<=n;i++){ for(ll j=0;j<ll(e[i].size());j++){ if(s[i]!=s[e[i][j]]){ k[s[i]].push_back(s[e[i][j]]); pt[s[e[i][j]]]++; } } } n=t; memset(f,-0x3f3f3f,sizeof(f)); f[g]=x[g]; for(ll i=1;i<=n;i++){ if(pt[i]==0){ tp.push(i); } } while(!tp.empty()){ ll u=tp.front(); tp.pop(); for(ll i=0;i<ll(k[u].size());i++){ ll v=k[u][i]; f[v]=max(f[v],f[u]+x[v]); pt[v]--; if(pt[v]==0) tp.push(v); } } for(ll i=1;i<=n;i++){ if(y[i]==1) ans=max(ans,f[i]); } cout<<ans; }
- 1
Information
- ID
- 98
- Time
- 1000ms
- Memory
- 128MiB
- Difficulty
- 10
- Tags
- # Submissions
- 8
- Accepted
- 3
- Uploaded By