1977: [BeiJing2010组队]次小生成树 Tree
https://lydsy.com/JudgeOnline/problem.php?id=1977
题意:
求严格次小生成树,即边权和不能等于最小生成树。
分析:
倍增:求出最小生成树,然后枚举非树边,加入一条非树边,删掉环上的最大的边,如果最大的边等于加入的边,那么删掉环上次小的边。
LCT:直接维护链上最大值,与次大值。
代码:
倍增
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 100010; 11 const int M = 300010; 12 const LL INF = 1e18; 13 14 struct Edge{ 15 int u,v,w; 16 bool operator < (const Edge &A) const { 17 return w < A.w; 18 } 19 }e[M]; 20 int head[N],nxt[N<<1],to[N<<1],Enum; 21 int fa[N],deth[N],f[N][22]; 22 LL g1[N][22],g2[N][22],val[N<<1],Sum; 23 bool used[M]; //------ used[N] 24 25 inline void add_edge(int u,int v,int w) { 26 ++Enum; to[Enum] = v; val[Enum] = w; nxt[Enum] = head[u]; head[u] = Enum; 27 ++Enum; to[Enum] = u; val[Enum] = w; nxt[Enum] = head[v]; head[v] = Enum; 28 } 29 void dfs(int u,int fa) { 30 deth[u] = deth[fa] + 1; 31 for (int i=head[u]; i; i=nxt[i]) { 32 int v = to[i]; 33 if (v == fa) continue; // 写在下面了。。。 34 f[v][0] = u; 35 g1[v][0] = val[i]; // -- e[i].w 36 g2[v][0] = -INF; 37 dfs(v,u); 38 } 39 } 40 inline void get(LL a,LL b,LL &mx1,LL &mx2) { 41 if (a > mx1) mx2 = max(mx1,b); 42 else if (a == mx1) mx2 = max(mx2, b); 43 else if (a < mx1) mx2 = max(mx2, a); 44 mx1 = max(mx1,a); 45 } 46 inline LL solve(int u,int v,int w) { 47 if (deth[u] < deth[v]) swap(u,v); 48 int d = deth[u] - deth[v]; 49 LL mx1 = -INF, mx2 = -INF; 50 for (int i=20; i>=0; --i) { 51 if (d & (1 << i)) { 52 get(g1[u][i],g2[u][i],mx1,mx2); 53 u = f[u][i]; 54 } 55 } 56 if (u == v) return Sum + w - (mx1 < w ? mx1 : mx2); 57 for (int i=20; i>=0; --i) { 58 if (f[u][i] != f[v][i]) { // -- f[u][i]==f[u][i] 59 get(g1[u][i],g2[u][i],mx1,mx2); 60 get(g1[v][i],g2[v][i],mx1,mx2); 61 u = f[u][i], v = f[v][i]; 62 } 63 } 64 get(g1[u][0],g2[u][0],mx1,mx2); 65 get(g1[v][0],g2[v][0],mx1,mx2); 66 return Sum + w - (mx1 < w ? mx1 : mx2); 67 } 68 int find(int x) { 69 return x == fa[x] ? x : fa[x] = find(fa[x]); 70 } 71 int main() { 72 73 int n = read(),m = read(); 74 for (int i=1; i<=m; ++i) { 75 e[i].u = read(), e[i].v = read(), e[i].w = read(); 76 } 77 sort(e+1,e+m+1); 78 for (int i=1; i<=n; ++i) fa[i] = i; 79 int cnt = 0; 80 for (int i=1; i<=m; ++i) { 81 int u = find(e[i].u), v = find(e[i].v); 82 if (u != v) { 83 used[i] = true; 84 add_edge(e[i].u,e[i].v,e[i].w); 85 fa[u] = v; 86 Sum += e[i].w; 87 cnt++; 88 if (cnt == n-1) break; 89 } 90 } 91 dfs(1,0); 92 for (int j=1; j<=20; ++j) 93 for (int i=1; i<=n; ++i) { 94 int k = f[i][j-1]; 95 LL a1 = g1[i][j-1], a2 = g1[k][j-1]; 96 LL b1 = g2[i][j-1], b2 = g2[k][j-1]; 97 f[i][j] = f[k][j-1]; 98 g1[i][j] = max(a1, a2); 99 if (a1 == a2) g2[i][j] = max(b1, b2); 100 else { 101 g2[i][j] = min(a1, a2); 102 g2[i][j] = max(g2[i][j], max(b1, b2)); //--- 103 } 104 } 105 LL Ans = INF; // -- ANs = Sum 106 for (int i=1; i<=m; ++i) { 107 if (!used[i]) 108 Ans = min(Ans, solve(e[i].u,e[i].v,e[i].w)); 109 } 110 cout << Ans; 111 return 0; 112 }
LCT
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 100010; 11 const int M = 300010; 12 13 struct Edge{ 14 int u,v,w; 15 bool operator < (const Edge &A) const { 16 return w < A.w; 17 } 18 }e[M]; 19 int fa[N<<1],ch[N<<1][2],fir[N<<1],sec[N<<1],rev[N<<1],sk[N<<1],Top; 20 LL val[N<<1]; 21 int p[N]; 22 23 24 bool isroot(int x) { 25 return ch[fa[x]][0] != x && ch[fa[x]][1] != x; 26 } 27 int son(int x) { 28 return ch[fa[x]][1] == x; 29 } 30 void pushup(int x) { 31 int lc = ch[x][0], rc = ch[x][1]; 32 if (fir[lc] > fir[rc]) fir[x] = fir[lc], sec[x] = max(sec[lc], fir[rc]); 33 else if (fir[lc] < fir[rc]) fir[x] = fir[rc], sec[x] = max(sec[rc], fir[lc]); 34 else fir[x] = fir[lc], sec[x] = max(sec[lc], sec[rc]); 35 36 if (val[x] > fir[x]) sec[x] = fir[x], fir[x] = val[x]; 37 else if (val[x] < fir[x] && val[x] > sec[x]) sec[x] = val[x]; 38 } 39 void pushdown(int x) { 40 if (rev[x]) { 41 rev[ch[x][0]] ^= 1, rev[ch[x][1]] ^= 1; 42 swap(ch[x][0], ch[x][1]); 43 rev[x] ^= 1; 44 } 45 } 46 void rotate(int x) { 47 int y = fa[x],z = fa[y],b = son(x),c = son(y),a = ch[x][!b]; 48 if (!isroot(y)) ch[z][c] = x; fa[x] = z; 49 ch[x][!b] = y;fa[y] = x; 50 ch[y][b] = a; if (a) fa[a] = y; 51 pushup(y); pushup(x); 52 } 53 void splay(int x) { 54 sk[Top = 1] = x; 55 for (int i=x; !isroot(i); i=fa[i]) sk[++Top] = fa[i]; 56 while (Top) pushdown(sk[Top--]); 57 while (!isroot(x)) { 58 int y = fa[x]; 59 if (isroot(y)) rotate(x); 60 else { 61 if (son(x) == son(y)) rotate(y), rotate(x); 62 else rotate(x), rotate(x); 63 } 64 } 65 } 66 void access(int x) { 67 for (int last=0; x; last=x,x=fa[x]) { 68 splay(x); ch[x][1] = last; pushup(x); 69 } 70 } 71 void makeroot(int x) { 72 access(x); splay(x); rev[x] ^= 1; 73 } 74 int find(int x) { 75 return x == p[x] ? x : p[x] = find(p[x]); 76 } 77 78 int main() { 79 int n = read(),m = read(),Index = n; 80 for (int i=1; i<=n; ++i) p[i] = i; 81 for (int i=1; i<=m; ++i) { 82 e[i].u = read(), e[i].v = read(), e[i].w = read(); 83 } 84 sort(e+1,e+m+1); 85 LL Sum = 0, Ans = 1e18; 86 for (int i=1; i<=m; ++i) { 87 int x = e[i].u, y = e[i].v; 88 int u = find(x), v = find(y); 89 if (u != v) { 90 makeroot(x); 91 fa[x] = ++Index; // 化边权为点权 92 fa[Index] = y; 93 fir[Index] = val[Index] = e[i].w; 94 Sum += e[i].w; 95 p[u] = v; 96 } 97 else { 98 makeroot(x); 99 access(y); 100 splay(y); 101 Ans = min(Ans, (LL)e[i].w - (e[i].w > fir[y] ? fir[y] : sec[y])); 102 } 103 } 104 cout << Ans + Sum; 105 return 0; 106 }
upd:2018.10.22
前几天模拟赛出了这道题,考试的时候写的,感觉比以前的好写些。
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #include<iostream> 6 #include<cctype> 7 #include<set> 8 #include<vector> 9 #include<queue> 10 #include<map> 11 #define fi(s) freopen(s,"r",stdin); 12 #define fo(s) freopen(s,"w",stdout); 13 using namespace std; 14 typedef long long LL; 15 16 char buf[100000], *p1 = buf, *p2 = buf; 17 #define nc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++) 18 inline int read() { 19 int x=0,f=1;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-1; 20 for(;isdigit(ch);ch=nc())x=x*10+ch-'0';return x*f; 21 } 22 23 const int N = 200005; 24 const int LOG = 18; 25 26 struct Edge{ 27 int u, v; LL w; 28 bool operator < (const Edge &A) const { 29 return w < A.w; 30 } 31 }e[N * 3], R[N * 3]; 32 33 struct ST{ 34 int x;LL mx, ci; 35 ST() { x = mx = ci = 0; } 36 }f[N][19]; 37 int head[N], to[N * 6], nxt[N * 6]; LL len[N * 6]; 38 int fa[N], deth[N]; 39 int n, m, En, tot; LL Sum; 40 41 ST operator + (const ST &A, const ST &B) { 42 ST res; res.x = B.x; 43 if (A.mx > B.mx) res.mx = A.mx, res.ci = max(A.ci, B.mx); 44 else if (B.mx > A.mx) res.mx = B.mx, res.ci = max(A.mx, B.ci); 45 else res.mx = A.mx, res.ci = max(A.ci, B.ci); 46 return res; 47 } 48 49 inline void add_edge(int u,int v,LL w) { 50 ++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En; 51 ++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En; 52 } 53 int find(int x) { 54 return x == fa[x] ? x : fa[x] = find(fa[x]); 55 } 56 void Kruskal() { 57 sort(e + 1, e + m + 1); 58 for (int i=1; i<=n; ++i) fa[i] = i; 59 for (int i=1; i<=m; ++i) { 60 int u = find(e[i].u), v = find(e[i].v); 61 if (u != v) { 62 fa[u] = v; Sum += e[i].w; 63 add_edge(e[i].u, e[i].v, e[i].w); 64 } 65 else R[++tot] = e[i]; 66 } 67 } 68 69 void dfs(int u,int pa) { 70 deth[u] = deth[pa] + 1; 71 for (int i=head[u]; i; i=nxt[i]) { 72 int v = to[i]; 73 if (v == pa) continue; 74 dfs(v, u); 75 f[v][0].x = u; 76 f[v][0].mx = len[i]; 77 } 78 } 79 80 void D(const ST &A) { 81 cerr << A.x << " " << A.mx << " " << A.ci << "\n"; 82 } 83 84 ST work(int u,int v) { 85 ST ans; //ans.mx = -1; ans.ci = -1; ans.x = 0; 86 if (deth[u] < deth[v]) swap(u, v); 87 int d = deth[u] - deth[v]; 88 for (int j=LOG; j>=0; --j) { 89 if ((d >> j) & 1) { 90 ans = ans + f[u][j]; // 顺序!!! 91 u = f[u][j].x; 92 // D(ans); 93 } 94 } 95 if (u == v) return ans; 96 for (int j=LOG; j>=0; --j) { 97 if (f[u][j].x != f[v][j].x) { 98 ans = ans + f[u][j]; ans = ans + f[v][j]; 99 u = f[u][j].x, v = f[v][j].x; 100 // D(ans); 101 } 102 } 103 return ans + f[u][0] + f[v][0]; 104 } 105 106 int main() { //fi("2.txt"); 107 108 // freopen("tree.in","r",stdin); 109 // freopen("tree.out","w",stdout); 110 111 n = read(), m = read(); 112 for (int i=1; i<=m; ++i) 113 e[i].u = read(), e[i].v = read(), e[i].w = read(); 114 sort(e + 1, e + m + 1); 115 Kruskal(); 116 dfs(1, 0); 117 118 for (int j=1; j<=LOG; ++j) 119 for (int i=1; i<=n; ++i) 120 f[i][j] = f[i][j - 1] + f[f[i][j - 1].x][j - 1]; 121 122 ST now; 123 LL Ans = 1e18; 124 for (int i=1; i<=tot; ++i) { 125 now = work(R[i].u, R[i].v); 126 if (R[i].w != now.mx) Ans = min(Ans, Sum - now.mx + R[i].w); 127 else if (now.ci) Ans = min(Ans, Sum - now.ci + R[i].w); 128 } 129 cout << Ans; 130 return 0; 131 }