Gym

来源:互联网 发布:保利投资顾问待遇知乎 编辑:程序博客网 时间:2024/06/03 18:59

传送门
//思路 : 先根据题意知道肯定是先要强联通缩点, 然后分析题意知道, 要使最远的距离的最小, 就要想到树的直径. 因为树的直径端点到树上的点的距离才最远, 然后要最小那么就枚举一下就行了.
AC Code

/** @Cain*/const int maxn=2e5+5;int dfn[maxn],low[maxn],bel[maxn];int head[maxn],cut[maxn],in[maxn];int pre[maxn];stack<int >S;int cnt,res,ans;int n,m;struct node{    int u,v; ll w;}s[maxn];vector<int >G[maxn];void init(){    Fill(dfn,0);Fill(low,0);Fill(in,0);    Fill(bel,0);Fill(s,0);Fill(cut,0);    memset(head,-1,sizeof(head));    for(int i=0;i<=n;i++){        G[i].clear();        pre[i] = inf;    }    cnt = 1;res = 0;}void tarjan(int fa,int u){    dfn[u] = low[u] = cnt++;    S.push(u);    for(int i=0; i<G[u].size();i++){        int nex = G[u][i];        if(fa == nex ) continue;        if(!dfn[nex]){            tarjan(u,nex);            low[u] = min(low[u],low[nex]);        }        else low[u] = min(low[u],dfn[nex]);    }    if(low[u] == dfn[u]){        res++;        while(1){            int v = S.top();            S.pop();            bel[v] = res;            pre[res] = min(pre[res],v);            if(v == u) break;        }    }}vector<node >g[maxn];ll dis1[maxn],dis2[maxn];ll max_len; int st,ed;void dd(int u, int fa, ll len,int flag){    //搜索这棵树的直径.    if(flag) dis1[u] = len;    if(!flag) dis2[u] = len;    if(flag && len > max_len) st = u, max_len = len;    for(int i = 0; i < g[u].size(); i++) {        int v = g[u][i].v;        if (v == fa) continue;        dd(v, u, len + g[u][i].w, flag);    }}void solve(){    scanf("%d%d",&n,&m);    init();    for(int i=0;i<m;i++){        int u,v; ll w;        scanf("%d%d%lld",&u,&v,&w);        s[i].u = u; s[i].v = v; s[i].w = w;        G[u].push_back(v);        G[v].push_back(u);    }    tarjan(-1,1);    for(int i=0;i<=n;i++) g[i].clear();    for (int i=0 ;i<m; i++){        int u = bel[s[i].u] , v = bel[s[i].v], w = s[i].w;        if(u != v){            g[u].push_back((node){0, v, w});            g[v].push_back((node){0, u, w});        }    }    Fill(dis1,0); Fill(dis2,0);    max_len = -1;    dd(1, -1, 0, 1);    ed = st;    max_len = -1;    dd(st, -1, 0, 1);    swap(st, ed);    dd(ed, -1, 0, 0);    ll cur = INF; int num = 0;    for(int i=1;i<=res;i++){        if(max(dis1[i],dis2[i]) < cur){            cur = max(dis1[i],dis2[i]);            num = pre[i];        }        if(max(dis1[i],dis2[i]) == cur){    //这里是一个坑点.            //要始终保证节点编号最小, 所以还要在可能的答案中选取一个较小的编号.            num = min(pre[i],num);        }    }    printf("%d %lld\n",num,cur);}int main(){    int t = 1 ;    scanf("%d",&t);    while(t--){    //    printf("Case %d: ", cas++);        solve();        //printf("\n");    }}
原创粉丝点击