【模板】Tarjan 缩点 + 最长路

来源:互联网 发布:适合抓握的鼠标 知乎 编辑:程序博客网 时间:2024/06/04 18:00
#include<cstdio>#include<iostream>#include<cstring>#include<stack>#include<queue>#define maxn 101000using namespace std;typedef long long ll;stack <ll> S;queue <ll> Q;ll w[maxn],scc[maxn],scc_cnt;ll fst1[maxn],fst2[maxn],nxt1[maxn],nxt2[maxn];ll tot1,tot2,ans;ll dis[maxn],dis1[maxn];ll ru[maxn],dfn[maxn],low[maxn],cnt;bool vis[maxn];struct edge{ll from,to;}es1[maxn<<2],es2[maxn<<1];void build1(ll ff,ll tt){    es1[++tot1] = (edge){ff,tt};    nxt1[tot1] = fst1[ff];    fst1[ff] = tot1;}void build2(ll ff,ll tt){    es2[++tot2] = (edge){ff,tt};    nxt2[tot2] = fst2[ff];    fst2[ff] = tot2;}void tarjan(ll u){    S.push(u);    dfn[u] = low[u] = ++cnt;    for(ll i = fst1[u];i;i = nxt1[i])    {        ll v = es1[i].to;        if(!dfn[v])        {            tarjan(v);            low[u] = min(low[u],low[v]);        }        else if(!scc[v])        low[u] = min(low[u],dfn[v]);    }    if(dfn[u] == low[u])    {        scc_cnt ++;        while(true)        {            ll t = S.top();            S.pop();            scc[t] = scc_cnt;            dis[scc_cnt] += w[t];            if(t == u) break;        }    }}void spfa(ll s){    memset(dis1,0,sizeof(dis1));    ans = max(ans,dis[s]);    dis1[s]=dis[s];     Q.push(s);    vis[s] = 1;    while(!Q.empty())    {        ll u = Q.front();        Q.pop();        vis[u] = 0;        for(ll i = fst2[u];i;i = nxt2[i])        {            ll v = es2[i].to;            if(dis1[u] + dis[v] > dis1[v])            {                dis1[v] = dis1[u]+dis[v];                ans = max(ans,dis1[v]);                if(!vis[v])                {                    Q.push(v);                     vis[v] = 1;                 }            }        }    }}int main(){    ll n,m;    scanf("%lld%lld",&n,&m);    for(ll i = 1;i <= n;i ++) scanf("%lld",&w[i]);    for(ll i = 1;i <= m;i ++)    {        ll ff,tt;        scanf("%lld%lld",&ff,&tt);        build1(ff,tt);    }    for(ll i = 1;i <= n;i ++) if(!dfn[i]) tarjan(i);    cout<<scc_cnt<<endl;  for(int i=1;i<=scc_cnt;i++) cout<<dis[i]<<" scc "<<endl;    for(ll i = 1;i <= tot1;i ++)    {        ll ff = es1[i].from;        ll tt = es1[i].to;        if(scc[ff] != scc[tt])        {            build2(scc[ff],scc[tt]);            cout<<scc[ff]<<"->"<<scc[tt]<<endl;         }    }    for(int i=1;i<=scc_cnt;i++) build2(0,i);    spfa(0);    printf("%lld",ans);    return 0;}最短路同理 处理Spfa即可
原创粉丝点击