每日一题 P2656 采蘑菇 强连通缩点 树形dp
蓝题,思路不算很难,题意可知强连通块上每条边的值都可一压榨干净,其他边最多走一次。因此先缩点,连通块内所有边的值先算出来,然后再重新构图,这时候是个无环图,跑一边动态规划输出最大值即可。
#include <bits/stdc++.h>
#define int long long
#define endl "\n"
#define MAXN 1000005
using namespace std;
struct EDGE
{
int to,w,next;
double co;
} edge[MAXN];
int head[MAXN],ptr;
void add_edge(int u,int v,int w,double co)
{
edge[++ptr].to=v;
edge[ptr].w=w;
edge[ptr].co=co;
edge[ptr].next=head[u];
head[u]=ptr;
}
int n,m,s;
int belong[MAXN],scc;
int val[MAXN];
int dfn[MAXN],low[MAXN];
int idx;
bool in_stk[MAXN];
stack<int> stk;
void tarjan(int now)
{
dfn[now]=low[now]=++idx;
stk.push(now);
in_stk[now]=1;
for(int p=head[now]; p; p=edge[p].next)
{
int to=edge[p].to;
if(!dfn[to])
{
tarjan(to);
low[now]=min(low[now],low[to]);
}
else if(in_stk[to])
low[now]=min(low[now],dfn[to]);
}
if(dfn[now]==low[now])
{
int temp;
scc++;
do
{
temp=stk.top();
belong[temp]=scc;
in_stk[temp]=0;
stk.pop();
}
while(temp!=now);
}
}
struct E
{
int u,v,w;double co;
}e[MAXN];
int get(int p)
{
int ret=0;
int res=e[p].w;
double co=e[p].co;
while(res)
ret+=res,res*=co;
return ret;
}
void dfs(int now)
{
for(int p=head[now];p;p=edge[p].next)
{
int to=edge[p].to,w=edge[p].w;
val[to]=max(val[to],val[now]+w);
dfs(to);
}
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int u,v,w;double co;
cin>>u>>v>>w>>co;
add_edge(u,v,w,co);
e[i].u=u,e[i].v=v,e[i].w=w,e[i].co=co;
}
cin>>s;
tarjan(s);
ptr=0;
memset(head,0,sizeof(head));
memset(edge,0,sizeof(edge));
for(int i=1;i<=m;i++)
{
int u=belong[e[i].u],v=belong[e[i].v],w=e[i].w;
if(u==v)
{
val[u]+=get(i);
continue;
}
add_edge(u,v,w,0);
}
dfs(belong[s]);
int ans=0;
for(int i=1;i<=scc;i++)
ans=max(ans,val[i]);
cout<<ans;
}