【题解】CF894E Ralph and Mushrooms (缩点)

【题解】CF894E Ralph and Mushrooms (缩点)

这是紫?给个解方程算法

考虑一条边若可以重复遍历说明一定有环,有环的话一定会把环上的蘑菇榨干,考虑一条边从全部到榨干的贡献是多少
\[ \sum_{i=0}^x (w-\sum_{j=0}^i j)=\sum_{i=0}^x (w-{i(i+1)\over 2}) \]
那么考虑解出\(x\)的值,根据初中知识解出来\(x=\lfloor{-1+\sqrt{1+8w}\over 2}\rfloor\),预处理\(\sum {i(i+1)\over 2}\)可以直接计算贡献(其实也可以解通项公式)

然后Tarjan缩点之后变成DAG上的DP,同时有点权和边权的DAG DP

时间复杂度\(O(n)\)

//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>

using namespace std;  typedef long long ll;   char __buf[1<<18],*__c=__buf,*__ed=__buf;
inline int qr(){
    register int ret=0,f=0;
    register char c=getchar();
    while(!isdigit(c))f|=c==45,c=getchar();
    while(isdigit(c)) ret=ret*10+c-48,c=getchar();
    return f?-ret:ret;
}

const int maxn=1e6+5;
struct E{int to,w;};
vector<E> e[maxn],e2[maxn];
inline void add(const int&fr,const int&to,const int&w){e[fr].push_back({to,w});}
inline void add2(const int&fr,const int&to,const int&w){
    e2[fr].push_back({to,w});
}
int n,m;
int qaq[maxn],cnt;
ll w[maxn],dp[maxn];
bool usd[maxn];
int low[maxn],dfn[maxn],in[maxn],stk[maxn],top,siz[maxn];
ll s[maxn];
 
void dfs(const int&now){
    stk[++top]=now; in[now]=1;
    low[now]=dfn[now]=++*dfn;
    for(auto t:e[now]){
        if(!dfn[t.to]) dfs(t.to),low[now]=min(low[now],low[t.to]);
        else if(in[t.to]) low[now]=min(dfn[t.to],low[now]);
    }
    if(low[now]==dfn[now]){
        ++cnt;
        int temp;
        do temp=stk[top--],in[temp]=0,qaq[temp]=cnt,++siz[cnt];
        while(temp!=now);
    }
}

ll Dp(const int&now){
    if(usd[now]) return dp[now];
    dp[now]=0;
    for(auto t:e2[now]) dp[now]=max(dp[now],Dp(t.to)+t.w);
    usd[now]=1;
    return dp[now]=w[now]+dp[now];
}

int main(){
    n=qr(); m=qr();
    for(int t=1,t1,t2,t3;t<=m;++t) t1=qr(),t2=qr(),t3=qr(),add(t1,t2,t3);
    for(int t=1;t<maxn;++t) s[t]=s[t-1]+(1ll*t*(t+1)>>1);
    int S=qr();
    dfs(S);
    for(int t=1;t<=n;++t)
        for(auto i:e[t]){
            if(qaq[t]==qaq[i.to]) {
                int k=(sqrt((long double)1+8ll*i.w)-1)/2.0;
                w[qaq[t]]=w[qaq[t]]+(k+1ll)*i.w-s[k];
            }
            else add2(qaq[t],qaq[i.to],i.w);
        }
    ll ans=Dp(qaq[S]);
    printf("%lld\n",ans);
    return 0;
}


猜你喜欢

转载自www.cnblogs.com/winlere/p/11807470.html
今日推荐