40分,玄关

P3387 【模板】缩点

是这样: 你的tarjan缩点是正确的,而重新建图部分你需要向新图添加所有原图的边。 即将 ```cpp for (int i = 1; i <= n; ++i){ int xx = fa[a[i]], yy = fa[b[i]]; if (xx != yy) { G[xx].push_back(yy); ++in[yy]; } } ``` 改为 ```cpp for (int i = 1; i <= m; ++i){ int xx = fa[a[i]], yy = fa[b[i]]; if (xx != yy) { G[xx].push_back(yy); ++in[yy]; } } ``` 然后你在topo sort中找到入度为零的点,就将它加入队列中了。没有验证它是否是这个强连通分量的“根节点”(即最早探索到的节点),这导致一个强连通分量的节点多次入队,造成错误。 这个错误的改法很多,这里只说一种:将所有强连通分量中的节点染成“根节点”的编号,并在入队时特判
by ENJOuYang @ 2024-01-21 12:06:51


```cpp #include <bits/stdc++.h> #define int long long using namespace std; const int N = 1e5 + 5; const int NR = 1e4 + 5; int n,m,dis[N],a[N],b[N],in[NR],fa[NR],dfn[NR],low[NR],dp[NR],cnt,sum,ans = -1; vector<int> g[NR]; vector<int> G[NR]; bool vis[NR]; stack<int> st; void Tarjan (int x){ st.push(x); vis[x] = 1; ++cnt; dfn[x] = cnt; low[x] = cnt; for (int i = 0; i < g[x].size(); ++i){ int nxt = g[x][i]; if (dfn[nxt] == 0){ Tarjan(nxt); low[x] = min (low[x], low[nxt]); }else if (vis[nxt] == 1){ low[x] = min (low[x], low[nxt]); } } if (dfn[x] == low[x]){ while (st.top() != x && !st.empty()){ //cout<<st.top()<<" "; int tmp = st.top(); st.pop(); fa[tmp] = x; vis[tmp] = 0; dis[x] += dis[tmp]; } fa[x]=x; //cout<<st.top()<<endl; vis[x] = 0; st.pop(); } return ; } void topo (){ queue<int> q; for (int i = 1; i <= n; ++i){ if (fa[i]==i && in[i] == 0){ q.push(i); dp[i] = dis[i]; } } while (!q.empty()){ int tmp = q.front(); q.pop(); for (int i = 0; i < G[tmp].size(); ++i){ int nxt = G[tmp][i]; dp[nxt] = max (dp[nxt], dp[tmp] + dis[nxt]); --in[nxt]; if (in[nxt] == 0) q.push(nxt); } } return ; } signed main (){ ios::sync_with_stdio(0); cin.tie(0);cout.tie(0); cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> dis[i]; for (int i = 1; i <= m; ++i){ cin >> a[i] >> b[i]; g[a[i]].push_back(b[i]); } for (int i = 1; i <= n; ++i){ if (dfn[i] == 0) Tarjan(i); } for (int i = 1; i <= m; ++i){ int xx = fa[a[i]], yy = fa[b[i]]; if (xx != yy) { G[xx].push_back(yy); ++in[yy]; } } //for (int i = 1; i <= n; ++i)cout<<fa[i]<<" "; //puts(""); topo(); for (int i = 1; i <= n; ++i) ans = max (ans, dp[i]); cout << ans << '\n'; return 0; } ```
by ENJOuYang @ 2024-01-21 12:11:47


@[HuYangMu2011](/user/632311) 不是有必要写 topo 吗,我 $n^2$ dfs 过了。
by Super_Builder @ 2024-01-21 13:50:34


@[HuYangMu2011](/user/632311) $n^2$ 建图不香吗,非要多开两个数组建图。 最后附上 AC 代码。 ```cpp #include <bits/stdc++.h> using namespace std; #define fst first #define scd second #define N 10005 int cnt=0,n,m,ww[N],dfn[N],low[N],vis[N],w[N],idx=0,scc[N]; vector<int>e[N],e2[N]; stack<int>stk; void tarjan(int u){ vis[u]=1; dfn[u]=low[u]=++cnt; stk.push(u); for(auto v:e[u]){ if(!dfn[v]){ tarjan(v); low[u]=min(low[u],low[v]); } else if(vis[v]){ low[u]=min(dfn[v],low[u]); } } if(dfn[u]==low[u]){ idx++; while(stk.top()!=u){ vis[stk.top()]=0; scc[stk.top()]=idx; stk.pop(); } vis[stk.top()]=0; scc[stk.top()]=idx; stk.pop(); } } int dfs(int u){ int maxx=0; for(auto v:e2[u]){ maxx=max(maxx,dfs(v)); } return maxx+w[u]; } int main(){ ios::sync_with_stdio(0); cin.tie(0),cout.tie(0); cin>>n>>m; for(int i=1;i<=n;i++)cin>>ww[i]; for(int i=1;i<=m;i++){ int u,v; cin>>u>>v; e[u].push_back(v); } for(int i=1;i<=n;i++){ if(!dfn[i])tarjan(i); } for(int i=1;i<=n;i++){ w[scc[i]]+=ww[i]; } for(int i=1;i<=n;i++){ for(auto v:e[i]){ if(scc[i]!=scc[v]) e2[scc[i]].push_back(scc[v]); } } int ans=0; // cout<<idx<<endl; for(int i=1;i<=idx;i++){ ans=max(ans,dfs(i)); } cout<<ans; return 0; } ```
by Super_Builder @ 2024-01-21 13:53:11


%%%%%@[Xu_dh](/user/820227)
by huyangmu @ 2024-01-22 08:03:13


已关%%%@[ouyang09](/user/798144)
by huyangmu @ 2024-01-22 09:16:22


|