11.04T3 次小生成树(the second smallest spanning tree)

3232 -- 【BJOI2010】次小生成树(the second smallest spanning tree)

Description

  Little C has learned a lot about algorithms for minimum spanning trees, such as Prim's algorithm, Kruskal's algorithm.
  Little P challenged Little C to find the second smallest spanning tree of an undirected graph, and this second smallest spanning tree had to be strictly the second smallest.
  This means: If the edge set selected by the minimum spanning tree is EM, and the edge set selected by the strictly second smallest spanning tree is ES, then it must satisfy: (value(e) represents the weight of edge e).
      

Input

  The first line contains two integers N and M, representing the number of vertices and edges in the undirected graph, respectively.
  The following M lines, each contain three numbers x, y, z, indicating that there is an edge between vertex x and vertex y, with the edge weight being z.

Output

  The output contains one line, with only one number, representing the total weight of the edges of the strictly second smallest spanning tree. (It is guaranteed that a strictly second smallest spanning tree exists.)

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

Hint

In the data, the undirected graph has no self-loops;
For 50% of the data, N≤2000, M≤3000;
For 80% of the data, N≤50000, M≤100000;
For 100% of the data, N≤100000, M≤300000,
and the edge weights are non-negative and do not exceed 10^9.

Source

xinyue
 
 
 
 

分析:最小生成树,倍增法

首先考虑不严格的次小生成树

我们先求出最小生成树,然后对每条不在最小生成树的边(x,y),求出x->y路径上的最大的边,把它替换这条边之后的树就可能是次小生成树

用倍增思想记录max[x][i]表示x的第2^i的祖先到x的边上的最大值就可以做到O(nlogn)

严格次小稍微有些区别,如果路径最大边和边(x,y)权值相同,就不能替换,而要换严格次大的边,所以多记一个secmax[x][i]表示x的第2^i的祖先到x的边上的严格最大值即可

 

Analysis: Minimum Spanning Tree, LCA(nearest common ancestor)

First, consider the non-strict second smallest spanning tree.

We first find the minimum spanning tree, and then for every edge (x, y) that is not in the minimum spanning tree, we find the largest edge on the path from x to y. Replacing this edge with the new edge may result in a second smallest spanning tree.

Using the binary lifting concept, we can record max[x][i] to represent the maximum value of the edge on the path from x to its 2^i-th ancestor, which can be solved in O(nlogn).

For the strictly second smallest tree, it is slightly different. If the maximum edge on the path is of the same weight as edge (x, y), we cannot replace it. Instead, we should replace it with the strictly second largest edge. Therefore, we also need to keep a record of secmax[x][i], which represents the strictly second largest edge value on the path from x to its 2^i-th ancestor.

 

code:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<algorithm>
  4 #include<cstring>
  5 #define N 300005
  6 using namespace std;
  7 struct node {
  8     int u,v,w,tag;
  9 } t[N],e[N];
 10 int first[N],nxt[N],cnt;
 11 void add(int u,int v,int w) {
 12     e[++cnt].u=u;
 13     e[cnt].v=v;
 14     e[cnt].w=w;
 15     nxt[cnt]=first[u];
 16     first[u]=cnt;
 17 }
 18 int fa[N];
 19 int find(int x) {
 20     if(x!=fa[x])return fa[x]=find(fa[x]);
 21     return fa[x];
 22 }
 23 void merge(int x,int y) {
 24     int f1=find(x),f2=find(y);
 25     if(f1!=f2)fa[f1]=f2;
 26 }
 27 long long sum=0;
 28 int n,m;
 29 void kruskal() {
 30     int cnt_=0;
 31     for(int i=1; i<=m; i++) {
 32         int u=t[i].u,v=t[i].v;
 33         if(find(u)!=find(v)) {
 34             merge(u,v);
 35             add(u,v,t[i].w);
 36             add(v,u,t[i].w);
 37             t[i].tag=1;
 38             sum+=t[i].w;
 39             cnt_++;
 40             if(cnt_==n-1)return;
 41         }
 42     }
 43 }
 44 int f[N][30],dep[N],mx[N][30],smx[N][30];
 45 void dfs(int x) {
 46     for(int i=first[x]; i; i=nxt[i]) {
 47         int v=e[i].v;
 48         if(v==f[x][0])continue;
 49         mx[v][0]=e[i].w;
 50         smx[v][0]=-1;
 51         dep[v]=dep[x]+1;
 52         f[v][0]=x;
 53         dfs(v);
 54     }
 55 }
 56 pair<int,int> lca(int x,int y) {
 57     int max0=-1;
 58     int smax0=-1;
 59     if(dep[x]<dep[y])swap(x,y);
 60     for(int i=19; i>=0; i--) {
 61         if(dep[f[x][i]]>=dep[y]) {
 62             if(max0<mx[x][i]) {
 63                 smax0=max0;
 64                 max0=mx[x][i];
 65             }
 66             smax0=max(smax0,smx[x][i]);
 67             max0=max(max0,mx[x][i]);
 68             x=f[x][i];
 69         }
 70         if(x==y)return make_pair(max0,smax0);
 71     }
 72     for(int i=19; i>=0; i--) {
 73         if(f[x][i]==f[y][i]) continue;
 74         if(mx[x][i]>max0) {
 75             smax0=max0;
 76             max0=mx[x][i];
 77         } else if(mx[x][i]<max0) {
 78             smax0=max(smax0,mx[x][i]);
 79         }
 80         if(mx[y][i]>max0) {
 81             smax0=max0;
 82             max0=mx[y][i];
 83         } else if(mx[y][i]<max0) {
 84             smax0=max(smax0,mx[y][i]);
 85         }
 86         smax0=max(smax0,max(smx[x][i],smx[y][i]));
 87         max0=max(max0,max(mx[x][i],mx[y][i]));
 88         x=f[x][i];
 89         y=f[y][i];
 90     }
 91     max0=max(mx[x][0],max(max0,mx[y][0]));
 92     if(mx[x][0]<max0) {
 93         smax0=max(smax0,mx[x][0]);
 94     }
 95     if(mx[y][0]<max0) {
 96         smax0=max(smax0,mx[y][0]);
 97     }
 98     return make_pair(max0,smax0);
 99 }
100 bool cmp(const node&a,const node&b) {
101     return a.w<b.w;
102 }
103 int main() {
104     ios::sync_with_stdio(false);
105     cin>>n>>m;
106     for(int i=1; i<=n; i++)fa[i]=i;
107     for(int i=1; i<=m; i++) {
108         int u,v,w;
109         cin>>t[i].u>>t[i].v>>t[i].w;
110     }
111     sort(t+1,t+m+1,cmp);
112     kruskal();
113     memset(smx,-1,sizeof f);
114     memset(mx,-1,sizeof mx);
115     f[1][0]=1;
116     dfs(1);
117     for(int i=1; i<=19; i++) {
118         for(int j=1; j<=n; j++) {
119             f[j][i]=f[f[j][i-1]][i-1];
120             mx[j][i]=max(mx[j][i-1],mx[f[j][i-1]][i-1]);
121             if(mx[j][i-1]!=mx[f[j][i-1]][i-1]) {
122                 smx[j][i]=max(smx[j][i],min(mx[j][i-1],mx[f[j][i-1]][i-1]));
123                 smx[j][i]=max(smx[j][i],max(smx[j][i-1],smx[f[j][i-1]][i-1]));
124             } else {
125                 smx[j][i]=max(smx[j][i-1],smx[f[j][i-1]][i-1]);
126             }
127         }
128     }
129     int delta=999999;
130     for(int i=1; i<=m; i++) {
131         if(t[i].tag)continue;
132         pair<int,int> now=lca(t[i].u,t[i].v);
133         if(t[i].w==now.first) {
134             delta=min(delta,t[i].w-now.second);
135             continue;
136         }
137         delta=min(delta,t[i].w-now.first);
138     }
139     cout<<sum+delta;
140     return 0;
141 }

over

posted @ 2018-11-04 19:02  saionjisekai  阅读(207)  评论(0编辑  收藏  举报