codeforces 894 E(scc + dp)

题目链接

E. Ralph and Mushrooms

分析

很显然如果在同一个连通分量内,它可以重复踩直到踩完.而重复踩,能踩到的蘑菇数可以预处理,然后二分求得.

那么我们将它求强连通再缩点后,问题就简单了,求出每个scc的权值作为节点权值,然后dp就行.

感觉本人代码有点搓,估计是很久没写过 scc缩点了,等会儿去看看大佬的姿势再更

AC code


#include 
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 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]1],sum[t]=tmp[t]+sum[t-1];
     cin>>n>>m;
     for(int i=0 ; iint 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;
}

你可能感兴趣的:(算法刷题)