20分, hack数据和大部分都过了,求助
查看原帖
20分, hack数据和大部分都过了,求助
370532
SuAnRan楼主2023/7/18 11:04
/*

先用kurskal求最小,然后其他非最小树边添加一条一定会形成环,再用这条边代替环中最大和次大的边,最后求个最小值

*/

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;
typedef long long LL;
typedef pair<int, int > PII;

const int N = 100010;
struct edge
{
    int a, b, w;
    bool f = false;

    bool operator< (const edge &t) const
    {
        return w < t.w;
    }

} edges[600010];

int n, m;
vector<PII> ve[N];
int d1[N][20]; //第i个节点向上跳2^j,最大的边长;
int d2[N][20]; //第i个节点向上跳2^j,次大的边长;
int fa[N][20];

int deep[N];

// kruskal 求最小生成树
LL sum;
int pa[N];

int find(int x)
{
    if(pa[x] != x) pa[x] = find(pa[x]);
    return pa[x];
}

void kruskal()
{
    for(int i = 1; i <= n; i ++) pa[i] = i;

    sort(edges, edges + m);

    for(int i = 0; i < m; i ++)
    {
        int a = find(edges[i].a), b = find(edges[i].b), w = edges[i].w;
        if(a != b)
        {
            pa[a] = b;
            sum += w;
            edges[i].f = true;
        }
    }
}

void Build()
{
    for(int i = 0; i < m; i ++)
    {
        int a = edges[i].a;
        int b = edges[i].b;
        int w = edges[i].w;
        //cout << i << edges[i].f << endl;
        if(edges[i].f)
        {
            //cout << a << " " << b << " " << w << endl;
            ve[a].push_back({b, w});
            ve[b].push_back({a, w});
           // cout << ve[a].size() << " " << ve[b].size() << endl;
        }
    }
}

void dfs(int u, int father)
{
    deep[u] = deep[father] + 1;
    fa[u][0] = father;

    for(int i = 1; i <= 18; i ++)
    {
        int j = fa[u][i - 1];

        fa[u][i] = fa[j][i - 1];

        d1[u][i] = d2[u][i] = -0x3f3f3f3f;
        
        int dis[4] = {d1[j][i - 1], d1[u][i - 1], d2[j][i - 1], d2[u][i - 1]};

        for(int k = 0; k < 4; k ++)
        {
            int op = dis[k];
            if(op > d1[j][i]) d2[j][i] = d1[j][i], d1[j][i] = op;
            else if(op > d2[j][i]) d2[j][i] = op;
        }
        
        //cout << u << " " << i << " " << d1[u][i] << " " << d2[u][i] << endl;
    }

    for(int i = 0; i < ve[u].size(); i ++)
    {
        auto j = ve[u][i];
        if(j.first != father)
        {
            d1[j.first][0] = j.second;
            d2[j.first][0] = -0x3f3f3f3f;
            dfs(j.first, u);
        }
    }
}

int lca(int u, int v, int w)
{
    int dis[100010], cnt = 0;

    if(deep[u] < deep[v]) swap(u, v);

    for(int i = 17; i >= 0; i --)
    {
        if(deep[fa[u][i]] >= deep[v])
        {
            dis[++ cnt] = d1[u][i];
            dis[++ cnt] = d2[u][i];
            u = fa[u][i];
        }
    }

    if(u != v)
    {
        for(int i = 17; i >= 0; i --)
        {
            if(fa[u][i] != fa[v][i])
            {
                dis[++ cnt] = d1[u][i];
                dis[++ cnt] = d2[u][i];
                dis[++ cnt] = d1[v][i];
                dis[++ cnt] = d2[v][i];
                u = fa[u][i];
                v = fa[v][i];
            }
        }

        dis[++ cnt] = d1[u][0];
        dis[++ cnt] = d1[v][0];
        dis[++ cnt] = d2[u][0];
        dis[++ cnt] = d2[v][0];
    }

    int dist1 = -0x3f3f3f3f, dist2 = -0x3f3f3f3f;

    for(int i = 1; i <= cnt; i ++)
    {
        //if(dis[i] == dist1) continue;
        if(dis[i] > dist1) dist2 = dist1, dist1 = dis[i];
        else if(dis[i] > dist2) dist2 = dis[i];
        //cout << i << dis[i] << endl;
    }
    //cout << dist1 << " " << dist2 << endl;
    if(w > dist1) return w - dist1;
    if(w > dist2) return w - dist2;
    else return 0x3f3f3f3f;
}
int main()
{
    cin >> n >> m;

    for(int i = 0; i < m; i ++)
    {
        int a, b, w;
        cin >> a >> b >> w;
        edges[i] = {a, b, w};
    }

    kruskal();

    Build();

    d1[1][0] = 0;
    d2[1][0] = -0x3f3f3f3f;

    dfs(1, 0);

    LL ans = 0x3f3f3f3f;

    for(int i = 0; i < m; i ++) // 遍历所有非最短树边
    {
        if(!edges[i].f)
        {
            ans = min(ans, sum + lca(edges[i].a, edges[i].b, edges[i].w));
        }
    }

    cout << ans << endl;
    //cout << sum << endl;
    //cout << ve[3].size() << endl;
}
2023/7/18 11:04
加载中...