• 【洛谷 P4180】【模板】严格次小生成树[BJWC2010](倍增)


    题目链接
    题意如题。
    这题作为我们KS图论的T4,我直接打了个很暴力的暴力,骗了20分。。
    当然,我们KS里的数据范围远不及这题。
    这题我debug了整整一个晚上还没debug出来,第二天早上眼前一亮,改出来了。
    严格次小生成树,顾名思义,就是数值严格小于最小生成树的最大生成树。
    ( ext{邓杰:一个很暴力的方法就是,求出最小生成树后,枚举不在生成树里的边,把这条边加进去,然后就会形成一个环,把这个环里最大的边删掉,然后对新形成的生成树取最小值})
    其实正解应该是吧就是对这个“暴力”的优化。这个“环”其实去掉加的边后就是原数中这条边连接的两个点之间的路径,统计最大值就行了。由于是 严格 次小生成树,所以还要维护一个次大值。链上求最值,这个显然可以用树剖来实现,但此题是静态链上求最值,直接用倍增来维护就行了,具体的就在倍增跳LCA的时候统计最值就行了。

    #include <cstdio>
    #include <algorithm>
    #include <cstring>
    #include <queue>
    using namespace std;
    #define INF 2147483647
    #define Open(s) freopen(s".in","r",stdin);freopen(s".out","w",stdout);
    #define Close fclose(stdin); fclose(stdout);
    inline int read(){
    	int s = 0, w = 1;
    	char ch = getchar();
    	while(ch < '0' || ch > '9') { if(ch == '-') w = -1; ch = getchar(); }
    	while(ch >= '0' && ch <= '9') { s = s * 10 + ch - '0'; ch = getchar(); }
    	return s * w;
    }
    typedef long long ll;
    const int MAXN = 100010;
    const int MAXM = 300010;
    struct edge{
    	int from, to, dis;
    	bool operator < (const edge A) const{
    		return dis < A.dis;
    	}
    }s[MAXM];
    struct Edge{
    	int to, next, dis;
    }e[MAXN];
    int num, head[MAXN << 1];
    inline void Add(int from, int to, int dis){
        e[++num] = (Edge){ to, head[from], dis };
        head[from] = num;
    }
    int n, m;
    ll ans;
    int fa[MAXN], t[MAXN], flag, f[MAXN][23], dep[MAXN];
    ll Max[MAXN][23], SMax[MAXN][23];
    void init(){
    	for(int i = 1; i <= n; ++i) fa[i] = i;
    }
    int find(int x){
    	return fa[x] == x ? x : fa[x] = find(fa[x]);
    }
    void merge(int x, int y){
    	fa[find(y)] = find(x);
    }
    void DFS(int u, int fa){
        dep[u] = dep[fa] + 1;
        f[u][0] = fa;
        for(int i = head[u]; i; i = e[i].next)
           if(e[i].to != fa)
             Max[e[i].to][0] = e[i].dis, DFS(e[i].to, u);
    }
    int LCA(int u, int v, int Ans){
        ll MAX = 0, SMAX = 0;
        if(dep[u] < dep[v]) swap(u, v);
        int cha = dep[u] - dep[v];
        for(int i = 21; i >= 0; --i) 
           if(cha & (1 << i)){
             if(Max[u][i] > MAX){
               SMAX = MAX;
               MAX = Max[u][i];
             }
             else if(Max[u][i] != MAX && Max[u][i] > SMAX) SMAX = Max[u][i];
             if(SMax[u][i] > SMAX) SMAX = SMax[u][i];
             u = f[u][i];
           }
        for(int i = 21; i >= 0; --i)
           if(f[u][i] != f[v][i]){
             if(Max[u][i] > MAX){
               SMAX = MAX;
               MAX = Max[u][i];
             }
             else if(Max[u][i] != MAX && Max[u][i] > SMAX) SMAX = Max[u][i];
             if(SMax[u][i] > SMAX) SMAX = SMax[u][i];
             if(Max[v][i] > MAX){
               SMAX = MAX;
               MAX = Max[v][i];
             }
             else if(Max[v][i] != MAX && Max[v][i] > SMAX) SMAX = Max[v][i];
             if(SMax[v][i] > SMAX) SMAX = SMax[v][i];
             u = f[u][i], v = f[v][i];
           }
        if(u != v){
          if(Max[v][0] > MAX){
            SMAX = MAX;
            MAX = Max[v][0];
          }
          else if(Max[v][0] != MAX && Max[v][0] > SMAX) SMAX = Max[v][0];
          if(SMax[v][0] > SMAX) SMAX = SMax[v][0];
          if(Max[u][0] > MAX){
            SMAX = MAX;
            MAX = Max[u][0];
          }
          else if(Max[u][0] != MAX && Max[u][0] > SMAX) SMAX = Max[u][0];
          if(SMax[u][0] > SMAX) SMAX = SMax[u][0];
        }
        if(MAX == Ans) return SMAX;
        else return MAX;
    }
    int main(){
    	Open("milk");
    	n = read(); m = read();
    	init();
    	for(int i = 1; i <= m; ++i){
    	   s[i].from = read();
    	   s[i].to = read();
    	   s[i].dis = read();
    	}
    	sort(s + 1, s + m + 1);
    	int res = n - 1;
    	for(int i = 1; i <= m && res; ++i)
    	   if(find(s[i].from) != find(s[i].to)){
    		 merge(s[i].from, s[i].to);
             ans += s[i].dis;
             t[i] = 1;
             Add(s[i].from, s[i].to, s[i].dis);
             Add(s[i].to, s[i].from, s[i].dis);
           }
    	DFS(s[1].from, 0);
    	for(int i = 1; i <= 21; ++i)
           for(int j = 1; j <= n; ++j){
       	      f[j][i] = f[f[j][i - 1]][i - 1];
       	      Max[j][i] = max(Max[j][i - 1], Max[f[j][i - 1]][i - 1]);
       	      if(Max[j][i - 1] != Max[f[j][i - 1]][i - 1])
       	        SMax[j][i] = max(min(Max[j][i - 1], Max[f[j][i - 1]][i - 1]), max(SMax[j][i - 1], SMax[f[j][i - 1]][i - 1]));
              else SMax[j][i] = max(SMax[j][i - 1], SMax[f[j][i - 1]][i - 1]);
           }
        int ANS = INF;
        for(int i = 1; i <= m; ++i){
           if(!t[i]){
             ANS = min(ANS, s[i].dis - LCA(s[i].from, s[i].to, s[i].dis));
           }
        }
    	printf("%d
    ", ans + ANS);
    	Close;
    	//system("pause");
    	return 0;
    }
    
    
  • 相关阅读:
    Jquery
    JavaScript
    poj--2115 C Looooops
    poj--3970 party
    poj 1061 青蛙的约会
    hdu1250--Hat's Fibonacci
    2318--TOYS
    扩展欧几里得--让你一次刷个够
    关于大数加法的解法
    有关环形数组的约瑟夫问题
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/9549470.html
Copyright © 2020-2023  润新知