洛谷P3119草鉴定

题目

草鉴定,tarjan可以用来缩点,优化spfa的时间,

缩点之后就是一个\(DAG\)了,因此完全可以用来跑spfa上的最长路,然后枚举每条边,查看是否这条边的两个节点分别可以到达起点所在的强连通分量。(因为要返回到1点)。然后更新答案就可以了。

可是为什么要缩点呢,因为只能逆行一次,逆行之后通过在强连通分量上的点可以把强连通分量上的所有点全都遍历一次,最后还可以回到强连通分量上的起点,所以可以tarjan缩点。

#include <bits/stdc++.h>
using namespace std;
int n, m, lin[100010], lne[100100], lf[101000], dfn[100010], low[100100], vis[100100], belong[100100], dis[1001000], dis2[101000], color, tot, cnt, ans, cntne, cntf;
stack <int> s; 
int sum[100100];struct edg {
    int to, nex;
}e[1000100], f[1000100], ne[100100];
inline void add(int u, int v)
{               
    e[++cnt].to = v;
    e[cnt].nex = lin[u];
    lin[u] = cnt;
}               
inline void add2(int u, int v)
{
    ne[++cntne].to = v;
    ne[cntne].nex = lne[u];
    lne[u] = cntne;
}
inline void addf(int u, int v)
{
    f[++cntf].to = v;
    f[cntf].nex = lf[u];
    lf[u] = cntf;
}
inline void tarjan(int u)
{               
    dfn[u] = low[u] = ++tot;
    s.push(u); vis[u] = 1;
    for(int i = lin[u]; i; i = e[i].nex)
    {           
        int v = e[i].to;
        if(!dfn[v]) {       
            tarjan(v);
            low[u] = min(low[u],low[v]);
        }       
        else if(vis[v]) low[u] = min(low[u],dfn[v]);
    }           
    if(low[u] == dfn[u])
    {
        int v = -3;
        color++;
        do
        {
            v = s.top(); s.pop();
            belong[v] = color;
            vis[v] = 0;
            sum[color]++;
        } while (u != v);
    }
}
int inq[101000]; 
inline void spfa()
{
    memset(dis, -123, sizeof(dis));
    queue <int> q;
    dis[belong[1]] = sum[belong[1]];
    q.push(belong[1]);
    while (!q.empty())
    {   
        int cur = q.front(); q.pop(); inq[cur] = 0;
        for (int i = lne[cur]; i; i = ne[i].nex)
        {
            int to = ne[i].to;
            if (dis[cur] + sum[to] > dis[to])
            {
                dis[to] = dis[cur] + sum[to];
                if (!inq[to])
                    inq[to] = 1, q.push(to);
            }
        }
    }
}
inline void sf()
{   
    memset(dis2, -123, sizeof(dis2));
    queue <int> q;
//  memset(vis, 0, sizeof(vis));
    dis2[belong[1]] = sum[belong[1]];

    q.push(belong[1]);
    while (!q.empty())
    {
        int cur = q.front(); q.pop(); inq[cur] = 0;
        for (int i = lf[cur]; i; i = f[i].nex)
        {
            int to = f[i].to;
            if(dis2[cur] + sum[to] > dis2[to])
            {
                dis2[to] = dis2[cur] + sum[to];
                if (!inq[to])
                    inq[to] = 1, q.push(to);
            }
        }
    }
}   
int b1[100100], b2[101000];
void dfs1(int u)
{
    b1[u] = 1;
    for (int i = lne[u]; i; i = ne[i].nex)
        if (!b1[ne[i].to])
            dfs1(ne[i].to);
}
void dfs2(int u)
{
    b2[u] = 1;
    for (int i = lf[u]; i; i = f[i].nex)
        if (!b2[f[i].to])
            dfs2(f[i].to);
}
inline void init()
{   
    scanf("%d%d", &n, &m);
    for (int i = 1, u, v; i <= m; i++)
        scanf("%d%d", &u, &v), add(u, v);
    for (int i = 1; i <= n; i++)
        if (!dfn[i]) tarjan(i);
        
}
inline void jiantu()
{   
    for (int i = 1; i <= n; i++)
        for (int j = lin[i]; j; j = e[j].nex)
        {
            int to = e[j].to;
            if (belong[i] != belong[to]) add2(belong[i], belong[to]), addf(belong[to], belong[i]);  
        }
}
int main()
{
    init(); 
    jiantu();
    dfs1(belong[1]);
    dfs2(belong[1]);
    spfa();
    sf();                 
    for (int i = 1; i <= color; i++)
        if (b1[i])        
            for (int j = lf[i]; j; j = f[j].nex)
                if (b2[f[j].to])
                    ans = max(ans, dis2[f[j].to] + dis[i]);
    ans -= sum[belong[1]];
    printf("%d\n", ans);      
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/liuwenyao/p/10850098.html