zoukankan      html  css  js  c++  java
  • 严格次小生成树(Bzoj1977:[Beijing2010组队]次小生成树)

    非严格次小生成树

    很简单,先做最小生成树
    然后枚举没加入的边加入,替换掉这个环内最大的边
    最后取(min)

    严格次小生成树

    还是一样的
    可以考虑维护一个严格次大值
    最大值和枚举的边相同就替换次大值的边
    否则替换最大值的边
    最后取(min)

    裸题

    Luogu
    随你用各种姿势(AC)

    (LCT)常数大,但是好写,开(O2)可以过

    # include <bits/stdc++.h>
    # define RG register
    # define IL inline
    # define Fill(a, b) memset(a, b, sizeof(a))
    using namespace std;
    typedef long long ll;
    const int _(4e5 + 5);
    
    IL ll Input(){
        RG ll x = 0, z = 1; RG char c = getchar();
        for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
        for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
        return x * z;
    }
    
    int ch[2][_], fa[_], rev[_], S[_], mx[_], _mx[_], val[_], anc[_];
    int n, m, ff[_], tt[_], w[_], id[_], vis[_];
    ll ans = 1e18, mst;
    
    # define ls ch[0][x]
    # define rs ch[1][x]
    
    IL int Son(RG int x){  return ch[1][fa[x]] == x;  }
    
    IL int Isroot(RG int x){  return ch[0][fa[x]] != x && ch[1][fa[x]] != x;  }
    
    IL void Update(RG int x){
        mx[x] = val[x], _mx[x] = -1;
    	if(mx[ls] > mx[x]) _mx[x] = mx[x], mx[x] = mx[ls];
    	else _mx[x] = max(mx[ls], _mx[x]);
    	if(mx[rs] > mx[x]) _mx[x] = mx[x], mx[x] = mx[rs];
    	else _mx[x] = max(mx[rs], _mx[x]);
    	_mx[x] = max(_mx[x], max(_mx[ls], _mx[rs]));
    }
    
    IL void Reverse(RG int x){
    	if(!x) return;
    	rev[x] ^= 1, swap(ls, rs);
    }
    
    IL void Pushdown(RG int x){
    	if(!rev[x]) return;
    	rev[x] = 0, Reverse(ls), Reverse(rs);
    }
    
    IL void Rotate(RG int x){
        RG int y = fa[x], z = fa[y], c = Son(x);
        if(!Isroot(y)) ch[Son(y)][z] = x; fa[x] = z;
        ch[c][y] = ch[!c][x]; fa[ch[c][y]] = y;
        ch[!c][x] = y; fa[y] = x;
    	Update(y);
    }
    
    IL void Splay(RG int x){
        RG int top = 0; S[++top] = x;
        for(RG int y = x; !Isroot(y); y = fa[y]) S[++top] = fa[y];
        while(top) Pushdown(S[top--]);
        for(RG int y = fa[x]; !Isroot(x); Rotate(x), y = fa[x])
            if(!Isroot(y)) Son(x) ^ Son(y) ? Rotate(x) : Rotate(y);
        Update(x);
    }
    
    IL void Access(RG int x){
    	for(RG int y = 0; x; y = x, x = fa[x]) Splay(x), rs = y, Update(x);
    }
    
    IL void Makeroot(RG int x){
    	Access(x), Splay(x), Reverse(x);
    }
    
    IL int Find(RG int x){
    	return anc[x] == x ? x : anc[x] = Find(anc[x]);
    }
    
    IL void Split(RG int x, RG int y){
    	Makeroot(x), Access(y), Splay(y);
    }
    
    IL void Link(RG int x, RG int y){
    	Makeroot(x), fa[x] = y;
    }
    
    IL int Cmp(RG int x, RG int y){  return w[x] < w[y];  }
    
    int main(RG int argc, RG char* argv[]){
        n = Input(), m = Input();
    	for(RG int i = 1; i <= n; ++i) val[i] = -1, anc[i] = i;
    	for(RG int i = 1; i <= m; ++i)
    		ff[i] = Input(), tt[i] = Input(), val[n + i] = w[i] = Input(), id[i] = i;
    	sort(id + 1, id + m + 1, Cmp);
    	for(RG int i = 1, j = 1; i <= m && j < n; ++i){
    		RG int fx = Find(ff[id[i]]), fy = Find(tt[id[i]]);
    		if(fx == fy) continue;
    		anc[fx] = fy, mst += w[id[i]], ++j, vis[id[i]] = 1;
    		Link(ff[id[i]], id[i] + n), Link(tt[id[i]], id[i] + n);
    	}
    	for(RG int i = 1; i <= m; ++i){
    		if(vis[i]) continue;
    		Split(ff[i], tt[i]);
    		if(mx[tt[i]] != w[i]) ans = min(ans, mst - mx[tt[i]] + w[i]);
    		else if(_mx[tt[i]] != w[i]) ans = min(ans, mst - _mx[tt[i]] + w[i]);
    	}
    	printf("%lld
    ", ans);
        return 0;
    }
    
    
  • 相关阅读:
    难以实践敏捷:估算
    使用AsyncEnumerator简化异步操作
    ESXi 入门配置
    学习模式,不如先了解问题
    我应该用哪种虚拟机?(一)
    在2003上实现Custom Task Pane
    我应该用哪种虚拟机?(终)
    我应该用哪种虚拟机?(二)
    正则表达式周二挑战赛 第十二周
    [译]Node中的ES6特性
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/8438564.html
Copyright © 2011-2022 走看看