Strictly small spanning tree [BJWC2010]

Original will point
the original title link

Title Description

Given a \ (N \) no point $ M $ to FIG edges, try to FIG Strictly small spanning tree.

Set the minimum spanning tree edge weights sum of \ (sum \) , Strictly small spanning tree refers to the right side of the sum is greater than \ (sum \) is a minimum spanning tree.

Input Format

The first line contains two integers \ (N \) and \ (M \) .

Next \ (M \) rows, each row containing three integers \ (X, Y, Z \) , represents the point \ (X \) and the point \ (Y \) is present before an edge weight of the edge is \ (z \) .

Output Format

Contains a line, only a number representing the right side Strictly small and spanning tree. (There must be strict to ensure that data spanning the second smallest)

data range

\ [N \ 10 ^ 5 \\\\ M \ 3 * 10 ^ 5 \]

Sample input:

5 6 
1 2 1 
1 3 2 
2 4 3 
3 5 4 
3 4 3 
4 5 6 

Sample output:

11

Report problem-solving

Understand the meaning of problems

You want to construct a \ (n \) nodes Strictly small spanning tree.

Parsing algorithm

Analysis Conditions

The key point of the title is given, that is rigorous and second smallest.

  1. What is strict

Is the subject of mandatory strict monotonicity can not have \ (= \) appears number.

  1. What is the second smallest

We should all know, minimum spanning tree, which requires the collection side of the sum of the minimum side , then the next smallest spanning tree, the sum of the side edge set of requirements only larger than the minimum spanning tree edge set of weights .

Summary nature

At least one (strictly) only a small difference between the times spanning tree, and the minimum spanning tree of an edge.And the truth is only a little difference, and that is the topic of human cancer

Let's prove it rough.(Forced perjury)

We know the minimum spanning tree, by \ (n-1 \) bar thereof.

Then the other \ (M-N + 1 \ ) is the extra edge .

If we say that an extra edge \ ((X, Y, Z) \) , was added to the minimum spanning tree, then it must be in \ ((x, y) \ ) on the path between to form a ring .

Well this ring above, the biggest edge is called
\ [Val_1 \]
times larger side , known as
\ [Val_2 \]
and in order to ensure strict in this monotonous nature, we have to set
\ [Val_1> Val_2 \ quad biggest edge must be greater than the next largest side \]
Next, we need a good analysis of what this extra edge up.

We know that extra edge, replacing any one side of a tree, will make the minimum spanning tree, no minimum

why?

Because on each side of the minimum spanning tree, it must satisfy the greedy nature of the smallest edge in.Why ah? Trust your instincts ah

The proof, Kruskal algorithm we use, has told us why.Only one truth, I'm lazy

All in all, words and short, we now know that this extra edge to join ., Will produce a non-minimum spanning tree .

We might as well make
\ [ans = right edge of the minimum spanning tree and \]
If you say that we will be extra edge, replace the maximum weight edge.
\ [Val_1 ==> z \\\ At this point we find the current Spanning Tree W = ans + z-val_1 \\\\ W = minimum spanning edges and the right of + plus extra edge - the maximum weight edge \]
this is a replacement, we can say that the spanning tree has the potential to become the next smallest spanning tree .

Then, we found that for a change edge of the second largest , is also possible.

We will be extra edge, forcibly replace the secondary side power value.
\ [Val_2 ==> Z \\\\ spanning this case W = ans + z-Val_2 \\\\ W = minimum spanning tree and +80 added extra edge - power times the value of the edge \]
now all candidates spanning trees are out, but we are facing a very serious problem.

How do we quickly calculate , on a path largest side, and the second largest edge.


Dynamic Programming

We may need to know the current status of is nothing more than two.

  1. On a path largest side
  2. On a path Strictly large side

So, we may wish to follow the idea of doubling the array , to create two new arrays.

  1. Maximum edge array
  2. Strictly large side arrays

\[ f[x][k]=f[fa[x][k-1]][k-1] \]

This is our very familiar Lca multiplier array .

Then in fact we are now, to grasp the hands of the most powerful nature is the most value properties .

We assume that a path is constructed three sections together.

Three sections, not on the three points.
\ [A => C, C => B, B => A \]

The second smallest spanning .png

We found
\ [A => B is in fact equal to the maximum \\\\ max (A => C maximum, B => C max) \]
This is the interval of values the best properties .

But Strictly large side, more trouble, do not panic, we slowly drawing to.

In order to respect the following brief, we set about the variable.
\ [A => C on the right side of the maximum Val_ {A, C} \ quad is the second largest edge weight V_ {A, C} \\\\ C => B on the maximum right side of Val_ {B, C} \ quad is the second largest edge weight V_ {B, C} \\\\ A => B on the right side of the maximum Val_ {A, B} \ quad is the second largest edge weight V_ {A, B} \\\\ \]
artifice look, Val multiple letters, so the right side is the largest, less letters V, so a large right side views.

We discuss classification, three cases.

The maximum value of the first paragraph ① = second segment maximum
\ [Val_ {A, C}
= Val_ {B, C} \] We unexpectedly found that the maximum value of as two.

The second largest edge weight can only
\ [V_ {A, B} = max (V_ {A, C}, V_ {B, C}) \]
② maximum first segment < second segment maximum.

So this time , the second largest edge weight is possible to take the first paragraph of the maximum.

Because the total segment maximum value, must be the maximum value of the second section.
\ [Val_ {A, B} = Val_ {B, C} \\\\ Thus V_ {A, B} can be = Val_ {A, C } \]
In summary, we conclude that.
\ [V_ {A, B} = max (Val_ {A, C}, V_ {B, C}) \]
③ maximum first segment > second segment maximum.

So this time, the second largest edge weight is to take the second stage maximum.

Because the total segment maximum value, must be the maximum value of the first segment.
\ [Val_ {A, B} = Val_ {A, C} \\\\ Thus V_ {A, B} can be = Val_ {B, C } \]
Similarly, sum up.
\ [V_ {A, B} = max (Val_ {B, C}, V_ {A, B}) \]
then we will \ (A, B, C \ ) embodied at .

A fact that is the starting node.

A jump is actually a C \ (2 ^ {i-1 } \) grid nodes.

A jump B in fact the \ (2 ^ {i} \ ) grid nodes.

Advertising time: discover still a little vague, we live lesson will explain very clearly, drawing certainly missed.


Code analysis

#include <bits/stdc++.h>
using namespace std;
#define INF 1e16
const int N=1e5+200;
const int M=6*1e5+300;
int head[M],edge[M],Next[M],ver[M],tot,fa[M],n,m,father[N][32],deep[N];
long long dp[2][N][32],val1,val2,ans_max,ans;
struct node
{
    int x,y,z,vis;
} s[M];
int cmp(node a,node b)
{
    return a.z<b.z;
}
struct Edge
{
    void init2()
    {
        memset(head,0,sizeof(head));
        tot=0;
    }
    void add_edge(int a,int b,int c)
    {
        edge[++tot]=b;
        ver[tot]=c;
        Next[tot]=head[a];
        head[a]=tot;
    }
    int find(int x)
    {
        return x==fa[x]?x:fa[x]=find(fa[x]);
    }
    void Kruskal()
    {
        sort(s+1,s+1+m,cmp);
        for(int i=1; i<=m; i++)
        {
            int a=find(s[i].x),b=find(s[i].y);
            if (a==b)
                continue;
            s[i].vis=1;
            fa[a]=b;
            ans+=s[i].z;
            add_edge(s[i].x,s[i].y,s[i].z);
            add_edge(s[i].y,s[i].x,s[i].z);
        }
    }
    void bfs(int root)
    {
        deep[root]=0;
        queue<int> q;
        q.push(root);
        while(q.size())
        {
            int x=q.front(),len=(int)log2(deep[x]+1);
            q.pop();
            for(int i=head[x]; i; i=Next[i])
            {
                int y=edge[i];
                if(y==father[x][0])
                    continue;
                deep[y]=deep[x]+1;
                father[y][0]=x,dp[0][y][0]=ver[i],dp[1][y][0]=-INF;
                q.push(y);
                for(int t=1; t<=len; t++)
                {
                    father[y][t]=father[father[y][t-1]][t-1];
                    if(dp[0][y][t-1]!=dp[0][father[y][t-1]][t-1])
                    {
                        dp[0][y][t]=max(dp[0][y][t-1],dp[0][father[y][t-1]][t-1]);
                        dp[1][y][t]=min(dp[0][y][t-1],dp[0][father[y][t-1]][t-1]);
                    }
                    else
                    {
                        dp[0][y][t]=dp[0][y][t-1];
                        dp[1][y][t]=max(dp[1][y][t-1],dp[1][father[y][t-1]][t-1]);
                    }
                }
            }
        }
    }
    inline void update2(int x)
    {
        if(x>val1)
            val2=val1,val1=x;
        else if(x>val2 && x!=val1)
            val2=x;
    }
    inline void update(int x, int t)
    {
        update2(dp[0][x][t]);
        update2(dp[1][x][t]);
    }
    inline void Lca(int x, int y)
    {
        val1=val2=-INF;
        if(deep[x]<deep[y])
            swap(x,y);
        while(deep[x]>deep[y])
        {
            int t=(int)log2(deep[x]-deep[y]);
            update(x,t),x=father[x][t];
        }
        if(x==y)
            return;
        for(int t=(int)log2(deep[x]); t>=0; t--)
        {
            if(father[x][t]!=father[y][t])
            {
                update(x,t),update(y,t);
                x=father[x][t];
                y=father[y][t];
            }
        }
        update(x,0),update(y,0);
    }
} g1;
int main()
{
//  freopen("stdin.in","r",stdin);
//  freopen("stdout.out","w",stdout);
    scanf("%d%d",&n,&m);
    g1.init2();
    for(int i=1; i<=m; i++)
    {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        s[i].x=a,s[i].y=b,s[i].z=c;
        fa[i]=i;
    }
    g1.Kruskal();
    g1.bfs(1);
    ans_max=INF;
    for(int i=1; i<=m; i++)
    {
        if(!s[i].vis)
        {
            g1.Lca(s[i].x,s[i].y);
            if(val1!=s[i].z)
                ans_max=min(ans_max,ans-val1+s[i].z);
            else
                ans_max=min(ans_max,ans-val2+s[i].z);
        }
    }
    printf("%lld\n",ans_max);
    return 0;
}

Guess you like

Origin www.cnblogs.com/gzh-red/p/11203598.html