[BZOJ1977]严格次小生成树
【问题描述】
小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。
正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)
这下小C蒙了,他找到了你,希望你帮他解决这个问题。
【输入格式】
第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点x和点y之间有一条边,边的权值为z。
【输出格式】
包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)
【输入样例】
5 6
1 2 1
1 3 2
2 4 3
3 5 4
3 4 3
4 5 6
【输出样例】
11
【数据范围】
数据中无向图无自环;
50% 的数据N≤2 000 M≤3 000;
80% 的数据N≤50 000 M≤100 000;
100% 的数据N≤100 000 M≤300 000 ,边权值非负且不超过 10^9 。
题解:
要求求严格次小生成树,首先kruskal就无法使用,prim复杂度太高
于是我们用LCA
构造出最小生成树,可知次小生成树肯定是加入某边再删去一边
假设加入(i,j)则有删去生成树上i~j路径最大的边,用倍增维护
但是严格次小没有解决
可以在用倍增维护最大值时,再维护次小值,那么当最大值等于加入边权值时则删去次大边
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 using namespace std; 6 typedef long long lol; 7 struct Messi 8 { 9 lol u,v; 10 lol dis; 11 }edge1[500001]; 12 struct Node 13 { 14 lol next,to; 15 lol dis; 16 }edge[100001]; 17 lol num,head[100001],set[100001],depth[100001],Max[100001][18],Max2[100001][18],fa[100001][18],n,m,ans1,ans=2e9; 18 bool vis[100001],b[500001]; 19 bool cmp(Messi a,Messi b) 20 { 21 return a.dis<b.dis; 22 } 23 void add(lol u,lol v,lol dis) 24 { 25 num++; 26 edge[num].next=head[u]; 27 head[u]=num; 28 edge[num].to=v; 29 edge[num].dis=dis; 30 } 31 lol find(lol x) 32 { 33 if (set[x]!=x) set[x]=find(set[x]); 34 return set[x]; 35 } 36 void dfs(lol x,lol dep) 37 {int i; 38 vis[x]=1; 39 depth[x]=dep; 40 for (i=1;i<=17;i++) 41 if (dep>(1<<i)) 42 { 43 Max[x][i]=max(Max[x][i-1],Max[fa[x][i-1]][i-1]); 44 if (Max[x][i-1]!=Max[fa[x][i-1]][i-1]) Max2[x][i]=Max[x][i-1]+Max[fa[x][i-1]][i-1]-Max[x][i]; 45 Max2[x][i]=max(Max2[x][i],max(Max2[x][i-1],Max2[fa[x][i-1]][i-1])); 46 fa[x][i]=fa[fa[x][i-1]][i-1]; 47 } 48 for (i=head[x];i;i=edge[i].next) 49 { 50 int v=edge[i].to; 51 if (vis[v]==0) 52 { 53 fa[v][0]=x; 54 Max[v][0]=edge[i].dis; 55 dfs(v,dep+1); 56 } 57 } 58 } 59 lol ask(lol x,lol y,lol d) 60 {int i; 61 lol s1=0,s2=0; 62 if (depth[x]<depth[y]) swap(x,y); 63 for (i=17;i>=0;i--) 64 if ((1<<i)<=depth[x]-depth[y]) 65 { 66 if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i])); 67 s2=max(s2,Max2[x][i]); 68 s1=max(s1,Max[x][i]); 69 x=fa[x][i]; 70 } 71 if (x==y) 72 { 73 if (s1==d&&s2) return d-s2; 74 else if (s2==0) return 2e9; 75 else if (s1!=d)return d-s1; 76 } 77 for (i=17;i>=0;i--) 78 { 79 if ((1<<i)<depth[x]&&fa[x][i]!=fa[y][i]) 80 { 81 if (s1!=Max[x][i]) s2=max(s2,min(s1,Max[x][i])); 82 s2=max(s2,Max2[x][i]); 83 s1=max(s1,Max[x][i]); 84 if (s1!=Max[y][i]) s2=max(s2,min(s1,Max[y][i])); 85 s2=max(s2,Max2[y][i]); 86 s1=max(s1,Max[y][i]); 87 x=fa[x][i];y=fa[y][i]; 88 } 89 } 90 if (s1!=Max[x][0]) s2=max(s2,min(s1,Max[x][0])); 91 s2=max(s2,Max2[x][0]); 92 s1=max(s1,Max[x][0]); 93 if (s1!=Max[y][0]) s2=max(s2,min(s1,Max[y][0])); 94 s2=max(s2,Max2[y][0]); 95 s1=max(s1,Max[y][0]); 96 x=fa[x][0];y=fa[y][0]; 97 if (s1==d&&s2) return d-s2; 98 else if (s2==0) return 2e9; 99 else if (s1!=d)return d-s1; 100 } 101 int main() 102 {int i,j,q,opt,x,y; 103 //freopen("scrip.in","r",stdin); 104 //freopen("scrip.out","w",stdout); 105 cin>>n>>m; 106 for (i=1;i<=m;i++) 107 { 108 scanf("%d%d%d",&edge1[i].u,&edge1[i].v,&edge1[i].dis); 109 } 110 sort(edge1+1,edge1+m+1,cmp); 111 for (i=1;i<=n;i++) 112 set[i]=i; 113 i=1;j=1; 114 while (i<=n-1&&j<=m) 115 { 116 int p=find(edge1[j].u),q=find(edge1[j].v); 117 if (p!=q) 118 { 119 set[p]=q; 120 i++; 121 b[j]=1; 122 ans1+=edge1[j].dis; 123 add(edge1[j].u,edge1[j].v,edge1[j].dis); 124 add(edge1[j].v,edge1[j].u,edge1[j].dis); 125 } 126 j++; 127 } 128 if (i<=n-1) 129 { 130 cout<<"No MST!"; 131 return 0; 132 } 133 dfs(1,1); 134 for (j=1;j<=m;j++) 135 { 136 if (b[j]==0) 137 { 138 ans=min(ans,ask(edge1[j].u,edge1[j].v,edge1[j].dis)); 139 } 140 } 141 if (ans==2e9) 142 { 143 cout<<"No SST!"; 144 return 0; 145 } 146 cout<<ans+ans1; 147 }