题目描述
小胖和ZYR要去ESQMS森林采蘑菇。
ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇。小胖和ZYR经过某条小径一次,可以采走这条路上所有的蘑菇。由于ESQMS森林是一片神奇的沃土,所以一条路上的蘑菇被采过后,又会长出一些新的蘑菇,数量为原来蘑菇的数量乘上这条路的“恢复系数”,再下取整。
比如,一条路上有4个蘑菇,这条路的“恢复系数”为0.7,则第一~四次经过这条路径所能采到的蘑菇数量分别为4,2,1,0.
现在,小胖和ZYR从S号小树丛出发,求他们最多能采到多少蘑菇。
对于30%的数据,N<=7,M<=15
另有30%的数据,满足所有“恢复系数”为0
对于100%的数据,N<=80,000,M<=200,000,0.1<=恢复系数<=0.8且仅有一位小数,1<=S<=N.
输入输出格式
输入格式:
第一行,N和M
第2……M+1行,每行4个数字,分别表示一条小路的起点,终点,初始蘑菇数,恢复系数。
第M+2行,一个数字S
输出格式:
一个数字,表示最多能采到多少蘑菇,在int32范围内。
输入输出样例
输入样例#:
3 3
1 2 4 0.5
1 3 7 0.1
2 3 4 0.6
1
输出样例#:
8
因为一个边可以走多次所以直接跑spfa肯定会t,所以我们可以用tarjan缩一下点,点权即为圈内的可以得到的蘑菇总数,再跑spfa就可以了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<stack>
#include<queue>
using namespace std;
const int SZ=401000;
struct edge
{
int f,t,d;
}es[SZ],es2[SZ];
int n,m,sss;
double k[SZ];
int l[SZ],r[SZ],size[SZ];
int tot,fst[SZ],nxt[SZ];
void build(int f,int t,int d)
{
es[++tot]=(edge){f,t,d};
nxt[tot]=fst[f];
fst[f]=tot;
}
void build2(int f,int t,int d)
{
es2[++tot]=(edge){f,t,d};
nxt[tot]=fst[f];
fst[f]=tot;
}
stack<int>s;
int dfn[SZ],low[SZ];
int scc[SZ],cnt,cnt2;
int mg[SZ];
int trajan(int u)
{
dfn[u]=low[u]=++cnt;
s.push(u);
for(int i=fst[u];i;i=nxt[i])
{
int v=es[i].t;//cout<<v<<" "<<dfn[v]<<endl;
if(!dfn[v])
{
low[v]=trajan(v);
low[u]=min(low[u],low[v]);
}
if(!scc[v]) low[u]=min(low[u],dfn[v]);
}
//cout<<u<<" "<<dfn[u]<<" "<<low[u]<<endl;
if(dfn[u]==low[u])
{
cnt2++;
while(1)
{
int ha=s.top();s.pop();
scc[ha]=cnt2;if(ha==u) break;
}
}
return low[u];
}
queue<int>q;
bool vis[SZ];
int dis[SZ],maxn;
void spfa(int ss)
{
vis[ss]=1;
q.push(ss);dis[ss]=mg[ss];
while(!q.empty())
{
int u=q.front();
q.pop();
vis[u]=0;
for(int i=fst[u];i;i=nxt[i])
{
int v=es2[i].t;
if(dis[v]<dis[u]+mg[v]+es2[i].d)
{
dis[v]=dis[u]+mg[v]+es2[i].d;
if(!vis[v])
{
vis[v]=1;
q.push(v);
}
}
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d%lf",&l[i],&r[i],&size[i],&k[i]);
build(l[i],r[i],size[i]);
}
scanf("%d",&sss);
trajan(sss);
for(int i=1;i<=m;i++)//缩点
{
if(scc[l[i]]==scc[r[i]])
{
while(size[i])
{
mg[scc[l[i]]]+=size[i];
//cout<<mg[scc[l[i]]]<<endl;
size[i]*=k[i];
}
}
}
memset(fst,0,sizeof(fst));
memset(nxt,0,sizeof(nxt));
tot=0;
for(int i=1;i<=m;i++)
{
if(scc[l[i]]!=scc[r[i]])
build2(scc[l[i]],scc[r[i]],size[i]);
}
spfa(scc[sss]);
for(int i=1;i<=cnt2;i++) maxn=max(maxn,dis[i]);
cout<<maxn;
return 0;
}