zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    【扫盲】i++和++i的区别
    java 字符串String.intern()方法学习
    随机访问和快速访问
    Semaphore信号量深度解析
    CyclicBarrier回环屏障深度解析
    CountDownLatch深度剖析
    静态代理和装饰者模式的区别
    AspectJ之@DeclareParents注解为对象添加新方法
    C#开发上位机常用
    使用Charles进行抓包、篡改请求、设置代理
  • 原文地址:https://www.cnblogs.com/mjtcn/p/9305054.html
Copyright © 2011-2022 走看看