原题链接

考察:LCA+Tarjan

思路:

        因为N<=1e5,所以上个算法N不适用.这里仍然是上道题的思路,枚举所有不在最小生成树的边.求出边两端点u,v.找到u,v在最小生成树的最大值d1和次大值d2.然后通过sum-d1(d2)+road[i].w求解答案.

        LCA优化的是求两端点之间的最大值.我们在找两端点u,v LCA的途中,先是将u,v跳至同一层,然后再跳到LCA处.在跳跃途中我们可以找到最大值和次大值.

       设d1[u,k] 表示当前结点u与fa[u][k]之间的最大值. d2[u,k] 表示当前结点u与fa[u][k]之间的次大值.

       假定k = 1. 那么d1[u,1] = max(d1[u][0],d1[fa[u][0],0) ----> 这样可以递推到k更大的时候 d1[u,k] = max(d1[u][k-1],d1[fa[u][k-1]][k-1])

       同理d2[u,k] 但是注意d2[u,k]是在 d1[u][k-1],d1[fa[u][k-1]][k-1],d2[u][k-1],d2[fa[u][k-1]][k-1] 之间求次大值.

      然后怎么获得两点的最长距离呢? 我们需要枚举所有跳到LCA途中的最大值和次大值.再在其中挑选最大值和次大值.

  1 #include <iostream>
  2 #include <cstring>
  3 #include <vector>
  4 #include <algorithm>
  5 #include <queue>
  6 using namespace std;
  7 const int N = 100010,M = 300010,INF = 0x3f3f3f3f,S = 140;
  8 typedef long long LL;
  9 struct Road{
 10     int fr,to,ne,w;
 11 }road[M<<1];
 12 struct Path{
 13     int u,v,w;
 14     bool use;
 15     bool operator<(const Path& p){
 16         return this->w<p.w;
 17     }
 18 }path[M];
 19 int n,m,idx,h[N],p[N],depth[N],fa[N][20],d1[N][20],d2[N][20];
 20 int temp[S];
 21 LL sum;
 22 void add(int a,int b,int c)
 23 {
 24     road[idx].w = c,road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
 25 }
 26 int findf(int x)
 27 {
 28     if(x!=p[x]) p[x] = findf(p[x]);
 29     return p[x];
 30 }
 31 void bfs(int s)
 32 {
 33     queue<int> q;
 34     memset(depth,0x3f,sizeof depth);
 35     depth[s] = 1; depth[0] = 0;
 36     q.push(s);
 37     while(q.size())
 38     {
 39         int u = q.front();
 40         q.pop();
 41         for(int i=h[u];~i;i=road[i].ne)
 42         {
 43             int v = road[i].to;
 44             if(depth[v]>depth[u]+1)
 45             {
 46                 depth[v] = depth[u]+1;
 47                 q.push(v);
 48                 fa[v][0] = u; d1[v][0] = road[i].w,d2[v][0] = -INF;//向上跳一步的最大距离.
 49                 for(int j=1;j<=18;j++)
 50                 {
 51                     fa[v][j] = fa[fa[v][j-1]][j-1];
 52                     d1[v][j] = max(d1[v][j-1],d1[fa[v][j-1]][j-1]);
 53                     int dis_1 = d1[v][j-1],dis_2 = d1[fa[v][j-1]][j-1];
 54                     int dis_3 = max(d2[v][j-1],d2[fa[v][j-1]][j-1]);
 55                     if(dis_1==dis_2) d2[v][j] = dis_3;
 56                     else if(dis_1>dis_2) d2[v][j] = max(dis_2,dis_3);//次大值
 57                     else if(dis_2>dis_1) d2[v][j] = max(dis_3,dis_1);
 58                 }
 59             }
 60         }
 61     }
 62 }
 63 int lca(int a,int b,int w)
 64 {
 65     int cnt = 0;//找跳跃途径中的最大值与次大值
 66     if(depth[a]<depth[b]) swap(a,b);
 67     int max_1 = -INF,max_2 = -INF;
 68     for(int i=18;i>=0;i--)
 69       if(depth[fa[a][i]]>=depth[b])//同层
 70       {
 71           temp[++cnt] = d1[a][i];
 72           temp[++cnt] = d2[a][i];
 73           a = fa[a][i];
 74       }
 75     if(a!=b)
 76     {
 77         for(int i=18;i>=0;i--)
 78           if(fa[a][i]!=fa[b][i])
 79           {
 80               temp[++cnt] = d1[a][i];  temp[++cnt] = d1[b][i];
 81               temp[++cnt] = d2[a][i];  temp[++cnt] = d2[b][i];
 82               a = fa[a][i],b = fa[b][i];
 83           }
 84         temp[++cnt] = d1[a][0]; temp[++cnt] = d1[b][0];
 85         temp[++cnt] = d2[b][0]; temp[++cnt] = d2[a][0];//最后还有一层
 86     }
 87     for(int i=1;i<=cnt;i++)
 88       if(temp[i]>max_1) max_2 = max_1,max_1 = temp[i];
 89       else if(temp[i]>max_2&&temp[i]!=max_1) max_2 = temp[i];
 90      if(w==max_1) return max_2;
 91      return max_1;
 92 }
 93 int main()
 94 {
 95     scanf("%d%d",&n,&m);
 96     for(int i=1;i<=n;i++) p[i] = i,h[i] = -1;
 97     for(int i=1;i<=m;i++)
 98     {
 99         int a,b,w; scanf("%d%d%d",&a,&b,&w);
100         path[i] = {a,b,w};
101     }
102     sort(path+1,path+m+1);
103     for(int i=1;i<=m;i++)
104     {
105         int pa =findf(path[i].u),pb = findf(path[i].v);
106         if(pa==pb) continue;
107         p[pa] = pb;
108         path[i].use = 1;
109         sum+=(LL)path[i].w;
110         add(path[i].u,path[i].v,path[i].w); add(path[i].v,path[i].u,path[i].w);
111     }
112     bfs(1);
113     LL ans = 1e18;
114     for(int i=1;i<=m;i++)
115       if(!path[i].use)
116       {
117           int a = path[i].u,b =path[i].v;
118           ans = min(sum-lca(a,b,path[i].w)+path[i].w,ans);
119       }
120     printf("%lld\n",ans);
121     return 0;
122 }