1977: [BeiJing2010组队]次小生成树 Tree

1977: [BeiJing2010组队]次小生成树 Tree

https://lydsy.com/JudgeOnline/problem.php?id=1977

题意:

  求严格次小生成树,即边权和不能等于最小生成树。

分析:

  倍增:求出最小生成树,然后枚举非树边,加入一条非树边,删掉环上的最大的边,如果最大的边等于加入的边,那么删掉环上次小的边。

  LCT:直接维护链上最大值,与次大值。

代码:

倍增

  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 }
View Code

LCT

  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 }
View Code

upd:2018.10.22

前几天模拟赛出了这道题,考试的时候写的,感觉比以前的好写些。

  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 << "
";
 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 }
View Code
原文地址:https://www.cnblogs.com/mjtcn/p/9305054.html