【洛谷 P2656】采蘑菇

好一次月赛,好一次良(bian)心(tai)的题目
我与靳小才那些不得不说的故事

因为有链接(懒得写),所以我就不上题面了~

这个题目,又是一道精彩的scc模(suan)板(fa)题

嗯,他们想尽可能多拿蘑菇,嗯
那一条边我能走几次走几次,有向图,想走几次走几次……?这是什么,告诉我——SCC!!!!
是的,就是SCC!
显然(其实没那么显然),scc上的边我可以尽可能的多拿走
just like

int get_val(int i)
{
    int ret = l[i].v;
    int nowval = l[i].v;
    while(1)
    {
        nowval = nowval * l[i].c;
        if(!nowval) return ret;
        ret += nowval;
    }
}

其中,l是边,v是权值,c是那个double

好的,就是这样,我们把scc上的搞完了
那么其他的呢……?
且慢……
不不不不不不是DAG好烦啊,咱把它搞成个DAG吧
嗯,好主意
来吧

    init();
    for(int i = 1;i <= m;i ++)
        if(scc_num[ff[i]] != scc_num[tt[i]])
            build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]);

恩恩
ff是记录的
恩恩
所谓……遍历边……?
恩恩
就是这样
但是,缩点之前,我们不妨先求个scc中的ans

要不,叫点权好了
嗯,是个好主意
那么怎么办呢
val,dfs吧
dfs??
枚举

枚举
对对对
枚举多棒
就是dfs()?
好像是一样呀
本来就应该一样
不过庄周梦蝶罢了

也就是这样了:

    for(int u = 1;u <= n;u ++)
        for(int i = first[u];~i;i = next[i])
            if(scc_num[u] == scc_num[l[i].t])
                val[scc_num[u]] += get_val(i);

然后,接下来是普通的言和 tarjan

int dfs_clock,dfn[MAXN];
int scc_cnt,scc_num[MAXN];
int low[MAXN];
stack <int> s;
void dfs(int u)
{
    low[u] = dfn[u] = ++dfs_clock;
    s.push(u);
    for(int i = first[u];i != -1;i = next[i])
    {
        int v = l[i].t;
        if(!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!scc_num[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u])
    {
        scc_cnt ++;
        while(true)
        {
            int x = s.top();
            s.pop();
            scc_num[x] = scc_cnt;
            if(x == u)
                break;
        }
    }
    return;
}

最后,跑个spfa什么的就好了
是最长路,最长路哦~~

int use[MAXN],dis[MAXN];
deque <int> q;
void spfa(int S)
{
    memset(use,0,sizeof(use));
    memset(dis,0x80,sizeof(dis));
    dis[S] = val[S];
    use[S] = true;
    q.push_back(S);
    q.push_back(80001);
    while(!q.empty())
    {
        int u = q.front();
        q.pop_front();
        use[u] = false;
        for(int i = first[u];i != -1;i = next[i])
        {
            int v = l[i].t;
            if(dis[v] < dis[u] + l[i].v + val[v])
            {
                dis[v] = dis[u] + l[i].v + val[v];
                if(use[v])
                    continue;
                if(dis[v] > dis[q.front()])
                    q.push_front(v);
                else
                    q.push_back(v);
                use[v] = true;
            }
        }
    }
    return;
}

顺带一提,ans要这样处理

    int ans = 0;
    for(int i = 1;i <= n;i ++)
        ans = max(ans,dis[i]);

总而言之,嘛
就是这样了

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
using namespace std;
const int MAXN = 80000 + 5;
const int MAXM = 200000 + 5;
struct edge
{
    int f,t,v;
    double c;
}l[MAXM << 1];
int first[MAXN],next[MAXN << 1],tot;
void init()
{
    memset(first,0xfff,sizeof(first));
    tot = 0;
    return;
}
void build(int f,int t,int v,double c)
{
    l[++tot] = (edge){f,t,v,c};
    next[tot] = first[f];
    first[f] = tot;
    return;
}
int dfs_clock,dfn[MAXN];
int scc_cnt,scc_num[MAXN];
int low[MAXN];
stack <int> s;
void dfs(int u)
{
    low[u] = dfn[u] = ++dfs_clock;
    s.push(u);
    for(int i = first[u];i != -1;i = next[i])
    {
        int v = l[i].t;
        if(!dfn[v])
        {
            dfs(v);
            low[u] = min(low[u],low[v]);
        }
        else if(!scc_num[v])
        {
            low[u] = min(low[u],dfn[v]);
        }
    }
    if(low[u] == dfn[u])
    {
        scc_cnt ++;
        while(true)
        {
            int x = s.top();
            s.pop();
            scc_num[x] = scc_cnt;
            if(x == u)
                break;
        }
    }
    return;
}
int val[MAXN];
int get_val(int i)
{
    int ret = l[i].v;
    int nowval = l[i].v;
    while(1)
    {
        nowval = nowval * l[i].c;
        if(!nowval) return ret;
        ret += nowval;
    }
}
int use[MAXN],dis[MAXN];
deque <int> q;
void spfa(int S)
{
    memset(use,0,sizeof(use));
    memset(dis,0x80,sizeof(dis));
    dis[S] = val[S];
    use[S] = true;
    q.push_back(S);
    q.push_back(80001);
    while(!q.empty())
    {
        int u = q.front();
        q.pop_front();
        use[u] = false;
        for(int i = first[u];i != -1;i = next[i])
        {
            int v = l[i].t;
            if(dis[v] < dis[u] + l[i].v + val[v])
            {
                dis[v] = dis[u] + l[i].v + val[v];
                if(use[v])
                    continue;
                if(dis[v] > dis[q.front()])
                    q.push_front(v);
                else
                    q.push_back(v);
                use[v] = true;
            }
        }
    }
    return;
}
int n,m,S;
int ff[MAXM],tt[MAXM],vv[MAXM];
double cc[MAXM];
void solve()
{
    scanf("%d",&S);
    dfs(S);
        for(int u = 1;u <= n;u ++)
            for(int i = first[u];~i;i = next[i])
                if(scc_num[u] == scc_num[l[i].t])
                    val[scc_num[u]] += get_val(i);
    init();
    for(int i = 1;i <= m;i ++)
        if(scc_num[ff[i]] != scc_num[tt[i]])
            build(scc_num[ff[i]],scc_num[tt[i]],vv[i],cc[i]);
    spfa(scc_num[S]);
    int ans = 0;
    for(int i = 1;i <= n;i ++)
        ans = max(ans,dis[i]);
    printf("%d\n",ans);
    return;
}
int main()
{
    init();
    scanf("%d %d",&n,&m);
    for(int i = 1;i <= m;i ++)
    {
        scanf("%d %d %d %lf",&ff[i],&tt[i],&vv[i],&cc[i]);
        build(ff[i],tt[i],vv[i],cc[i]);
    }
    solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值