【洛谷P2656】采蘑菇

#include<iostream>
#include<cstring>
#include<cstdio>
#include<stack>
#include<queue>
#include<cmath>
using namespace std;
struct in
{
    int to,ne,co;
}ter[200040];
double hui[200040];
bool flag[80080];
int n,m,x,y,z,s,ans[80080],f1[200020],l1[200020],c[200020],dfn[80080],low[80080],tot,ci,head[80080],tail,scc[80080],val[80080];
stack<int>sta;
queue<int>qwq;
inline void re(int &a)
{
    a=0;
    char b=getchar();
    bool flag=0;
    while(b<'0'||b>'9')
    {
        if(b=='-')
            flag=1;
        b=getchar();
    }
    while(b>='0'&&b<='9')
        a=a*10+b-'0',b=getchar();
    if(flag)
        a*=-1;
}
inline void init()
{
    memset(head,-1,sizeof(head));
    tail=0;
}
inline void build(int f,int l,int c)
{
    ter[++tail]=(in){l,head[f],c},head[f]=tail;
}
void dfs(int r)
{
    dfn[r]=low[r]=++ci;//先设初始值 
    sta.push(r);
    for(int i=head[r];i>0;i=ter[i].ne)
    {
        int t=ter[i].to;
        if(!dfn[t])//如果这个点没有访问过 
        {
            dfs(t);
            low[r]=min(low[r],low[t]);//在两个点能返回的层的最小值里面再取最小值 
        }
        else if(!scc[t])//如果这个点已经搜过但是没有判断在哪个环内 
            low[r]=min(low[r],dfn[t]); 
    }
    if(dfn[r]==low[r])//如果说从这个点出发并且能够回来(包括自环) 
    {
        tot++;
        while(1)
        {
            int h=sta.top();
            sta.pop();
            scc[h]=tot;
            if(h==r)//如果当前这个点已经被踢出 
                break;//结束 
        }
    }
    return;
}
inline int get_val(int x)//计算这个边的最大价值 
{
    int rt=ter[x].co;
    while(ter[x].co)
        ter[x].co*=hui[x],rt+=ter[x].co;
    return rt;
}
inline void ret()//重新建边,设置点权 
{
    for(int i=1;i<=n;i++)
        for(int j=head[i];j>0;j=ter[j].ne)
            if(scc[i]==scc[ter[j].to])//如果这两个点在同一个环里,加点权 
                val[scc[i]]+=get_val(j);
    init();//重新初始化建图 
    for(int i=1;i<=m;i++)
        if(scc[f1[i]]!=scc[l1[i]])//两者不同环,可以建边 
            build(scc[f1[i]],scc[l1[i]],c[i]);
}
void spfa()//像对普通点一样对于缩点后得到的dag跑最长路 
{
    for(int i=1;i<=n;i++)
        ans[i]=-1000000007;
    while(!qwq.empty())
        qwq.pop();
    qwq.push(scc[s]),ans[scc[s]]=val[scc[s]],flag[scc[s]]=1;
    while(!qwq.empty())
    {
        int qaq=qwq.front();
        for(int i=head[qaq];i>0;i=ter[i].ne)
        {
            int t=ter[i].to;
            if(ans[t]<ans[qaq]+val[t]+ter[i].co)
            {
                ans[t]=ans[qaq]+val[t]+ter[i].co;
                if(!flag[t])
                {
                    qwq.push(t);
                    flag[t]=1;
                }
            }
        }
        flag[qaq]=0;
        qwq.pop();
    }
    int mx=0;
    for(int i=1;i<=n;i++)//答案要取最大值 
        mx=max(mx,ans[i]);
    printf("%d",mx);
}
int main()
{
    re(n),re(m);
    init();
    for(int i=1;i<=m;i++)
        re(f1[i]),re(l1[i]),re(c[i]),scanf("%lf",&hui[i]),build(f1[i],l1[i],c[i]);
    re(s);
    dfs(s);//tarjan缩环 
    ret();//重新建边 
    spfa();//跑最长路 
    return 0;
}

 

posted @ 2017-10-30 23:42  那一抹落日的橙  阅读(248)  评论(0编辑  收藏  举报