题目链接
分析
很显然如果在同一个连通分量内,它可以重复踩直到踩完.而重复踩,能踩到的蘑菇数可以预处理,然后二分求得.
那么我们将它求强连通再缩点后,问题就简单了,求出每个scc的权值作为节点权值,然后dp就行.
感觉本人代码有点搓,估计是很久没写过 scc缩点了,等会儿去看看大佬的姿势再更
AC code
#include <bits/stdc++.h>
using namespace std;
#define ms(x,v) (memset((x),(v),sizeof(x)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define INF 0x3f3f3f3f
#define INF64 0x3f3f3f3f3f3f3f3f
typedef long long LL;
typedef pair<int,int > Pair;
const int maxn = 1e6 +10;
const int maxv = 1e8+10;
const int MOD = 1e9+7;
LL tmp[maxn],sum[maxn],t=0;
inline LL weight(LL x){
int p = lower_bound(tmp,tmp+t,x) - tmp-1;
return x*(p+1) - sum[p];
}
int n,m,s;
LL ans =0;
bool vis[maxn];
LL node[maxn],dp[maxn];//缩点后贡献
//scc
std::vector<int> sc_node[maxn];
std::vector<Pair> G[maxn];
int dfn[maxn],low[maxn];
int dfs_clock=0;
int scc[maxn],scc_cnt=0;
stack<int> S;//辅助栈
void dfs(int u) {
low[u] = dfn[u] = ++dfs_clock;
S.push(u);
for(auto e:G[u]){
int v = e.fi;
if(!dfn[v]){
//未访问
dfs(v);
low[u] = min(low[v],low[u]);
}else if(!scc[v])low[u] = min(low[v],low[u]);
}
//计算出low值之后看是否满足起始条件
if(low[u] == dfn[u]){
//标记
scc_cnt++;
while (true) {
int v = S.top();S.pop();
scc[v] = scc_cnt;
if(v == u)break;
}
}
}
LL solve(int u) {
if(dp[u]!=-1)return dp[u];
dp[u] = node[u];
LL ans = 0;
for(auto v : sc_node[u]){
for(auto e : G[v])
if(scc[e.fi] != u){
ans = max(ans,solve(scc[e.fi])+e.se);
}
}
return dp[u]+=ans;
}
int main(int argc, char const *argv[]) {
for(t=0; tmp[t-1]<maxv ; ++t)tmp[t] = t+ tmp[t-1],sum[t]=tmp[t]+sum[t-1];
cin>>n>>m;
for(int i=0 ; i<m ; ++i){
int x,y,w;
scanf("%d%d%d",&x,&y,&w );
G[x].pb(mp(y,w));
}
cin>>s;
for(int i=1 ; i<=n ; ++i)
if(!dfn[i])dfs(i);
for(int i=1 ; i<=n ; ++i){
sc_node[scc[i]].pb(i);
for(auto e: G[i]){
if(scc[e.fi]==scc[i])node[scc[i]]+=weight(e.se);
}
}
ms(dp,-1);
std::cout << solve(scc[s]) << '\n';
return 0;
}