luogu P3119 [USACO15JAN]草鑑定Grass Cownoisseur

這道題顯然要先 Tarjan 縮點預處理;
這裏就不多說了;
之後的點都是縮點之後點集;

我們考慮兩種點:

<1> 以 1 爲起點可以直接到達的; 我們這裏叫它一類點;
<2> 以該點爲起點,可以直接到達 1 的; 我們這裏叫它二類點;

所以我們先用 spfa 處理出來從 1 到這兩種點的點權值;
統計 ans 用;
然後枚舉每一個一類點;
由於我們只能走一次反邊;
所以我們所要的反邊一定與一類點和二類點相連;
因爲這樣才能確保從 1 出發,再回到 1 ;
所以我們可以確定一類點和二類點相連的邊一定滿足;
那麼我們枚舉這些邊;
然後統計所連兩點的點權和;
更新 ans ;
但是由於在一開始 spfa 處理時;
1 這個點的點權計算了兩遍;
所以最後要減掉;


#include "iostream"
#include "stdio.h"
#include "algorithm"
#include "vector"
#include "map"
#include "queue"
#define II int
#define R register
#define I 123546
using namespace std;


struct node {
    II to,up;
} aa[I], aa_1[I];

II head[I], DFN[I], LOW[I], is[I], stack[I], vis[I], belong[I], nu[I];

II inq[I], in_just[I], dis_back[I], in_back[I], dis_just[I], head_1[I], dis[I];

II _tot,n,m,_top,_num,bit,ans,_tot_1;

vector <II> just[I], back[I];

queue <II> Q;

void add(R II x,R II y)
{
    aa[++_tot].to=y;
    aa[_tot].up=head[x];
    head[x]=_tot;
}

void  add_1(R II x,R II y)
{
    aa_1[++_tot_1].to=y;
    aa_1[_tot_1].up=head_1[x];
    head_1[x]=_tot_1;
}


void Tarjan(R II x)
{
    DFN[x]=LOW[x]=++_num;
    stack[++_top]=x; vis[x]=1;
    for(R II i=head[x];i;i=aa[i].up) 
    {
        R II go=aa[i].to;
        if(!DFN[go]) {
            Tarjan(go);
            LOW[x]=min(LOW[x],LOW[go]);
        } else if(vis[go]) LOW[x]=min(LOW[x],DFN[go]);
    }

    if(LOW[x]==DFN[x]) {
        bit++;
        do {
            R II o=stack[_top--];
            vis[o]=0;
            belong[o]=bit;
            nu[bit]++;
        } while (stack[_top+1]!=x) ;
    }
}


void dfs_just(R II x)
{
    in_just[x]=1;
    for(R II i=0;i<just[x].size();i++)
    {
        R II go=just[x][i];
        if(!in_just[go]) {
            dfs_just(go);
        }
    }
}


void dfs_back(R II x)
{
    in_back[x]=1;
    for(R II i=0;i<back[x].size();i++)
    {
        R II go=back[x][i];
        if(!in_back[go]) {
            dfs_back(go);
        }
    }
}


void spfa_just()
{
    for(R II i=1;i<=bit;i++) dis_just[i]=-1e9;
    Q.push(belong[1]); inq[belong[1]]=1;
    dis_just[belong[1]]=nu[belong[1]];

    while (!Q.empty()) {
        R II x=Q.front(); Q.pop(); inq[x]=0;
        for(R II i=0;i<just[x].size();i++)
        {
            R II go=just[x][i];
            if(dis_just[go]<dis_just[x]+nu[go]) {
                dis_just[go]=dis_just[x]+nu[go];
                if(!inq[go]) {
                    Q.push(go);
                    inq[go]=1;
                }
            }
        }
    }
}


void spfa_back()
{
    for(R II i=1;i<=bit;i++) dis_back[i]=-1e9;
    Q.push(belong[1]); inq[belong[1]]=1;
    dis_back[belong[1]]=nu[belong[1]];

    while (!Q.empty()) {
        R II x=Q.front(); Q.pop(); inq[x]=0;
        for(R II i=0;i<back[x].size();i++)
        {
            R II go=back[x][i];
            if(dis_back[go]<dis_back[x]+nu[go]) {
                dis_back[go]=dis_back[x]+nu[go];
                if(!inq[go]) {
                    Q.push(go);
                    inq[go]=1;
                }
            }
        }
    }
}


int main()
{
//  freopen("1.in","r",stdin);

    scanf("%d%d",&n,&m);
    for(R II i=1;i<=m;i++)
    {
        R II x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }

    for(R II i=1;i<=n;i++)
    {
        if(!DFN[i]) {
            Tarjan(i);
        }
    }
    // 縮點; 

    for(R II i=1;i<=n;i++)
    {
        for(R II j=head[i];j;j=aa[j].up)
        {
            R II go=aa[j].to;
            if(belong[go]!=belong[i]) {
                just[belong[i]].push_back(belong[go]);
                back[belong[go]].push_back(belong[i]);
            }
        }
    }
    // 建正反邊; 

    dfs_just(belong[1]);
    dfs_back(belong[1]);
    // 記錄一、二類點; 

    spfa_just();
    spfa_back();
    // 計算權值; 

    for(R II i=1;i<=bit;i++)
    {
        if(in_just[i]) {
            for(R II j=0;j<back[i].size();j++)
            {
                R II go=back[i][j];
                if(in_back[go]) {
                    ans=max(ans,dis_just[i]+dis_back[go]);
                }
            }
        }
    }
    // 枚舉合法的邊; 

    printf("%d\n",ans-nu[belong[1]]);
    // 減去 1 多算的的權值; 
    exit(0);
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章