zoukankan      html  css  js  c++  java
  • Solution 「CF 1023F」Mobile Phone Network

    \(\mathcal{Description}\)

      Link.

      有一个 \(n\) 个结点的图,并给定 \(m_1\) 条无向带权黑边,\(m_2\) 条无向无权白边。你需要为每条白边指定边权,最大化其边权和,并保证 \(m_2\) 条边都在最小生成树中。

      \(n,m_1,m_2\le5\times10^5\)

    \(\mathcal{Solution}\)

      先保证在 \(\text{MST}\) 中的限制——指定所有边权为 \(0\)。并求出此时的 \(\text{MST}\)。显然最优情况下,\(\text{MST}\) 的形态和现在一样。

      那么对于每一条不在 \(\text{MST}\) 上的黑边,相当于限制了一条树上路径的最大值。从小到大枚举这样的边,每个点维护一个指针(整体上就是一个并查集)指向第一个未被限制到父亲边权的祖先,暴力跳指针统计答案即可。

      复杂度 \(\mathcal O\left((m_1+m_2)\log(m_1+m_2)\right)\)

    \(\mathcal{Code}\)

    #include <cstdio>
    #include <algorithm>
    
    #define ww first
    #define uu second.first
    #define vv second.second
    
    const int MAXN = 5e5, MAXM = 1e6;
    int n, m1, m2, m, fa[MAXN + 5];
    int ecnt, head[MAXN + 5], trf[MAXN + 5], trc[MAXN + 5], dep[MAXN + 5];
    std::pair<int, std::pair<int, int> > eset[MAXM + 5];
    bool inmst[MAXM + 5];
    
    struct Edge { int to, cst, nxt; } graph[MAXN * 2 + 5];
    
    inline int rint () {
    	int x = 0; char s = getchar ();
    	for ( ; s < '0' || '9' < s; s = getchar () );
    	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
    	return x;
    }
    
    inline void link ( const int s, const int t, const int c ) {
    	graph[++ ecnt] = { t, c, head[s] };
    	head[s] = ecnt;
    }
    
    inline void init () { for ( int i = 1; i <= n; ++ i ) fa[i] = i; }
    
    inline int find ( const int x ) { return x ^ fa[x] ? fa[x] = find ( fa[x] ) : x; }
    
    inline bool unite ( int x, int y ) {
    	return ( x = find ( x ) ) ^ ( y = find ( y ) ) ? fa[x] = y, true : false;
    }
    
    inline void DFS ( const int u ) {
    	for ( int i = head[u], v; i; i = graph[i].nxt ) {
    		if ( ( v = graph[i].to ) ^ trf[u] ) {
    			trf[v] = u, trc[v] = graph[i].cst, dep[v] = dep[u] + 1;
    			DFS ( v );
    		}
    	}
    }
    
    int main () {
    	n = rint (), m = ( m1 = rint () ) + ( m2 = rint () );
    	init ();
    	for ( int i = 1; i <= m1; ++ i ) {
    		eset[i].uu = rint (), eset[i].vv = rint ();
    		eset[i].ww = 0;
    	}
    	for ( int i = m1 + 1; i <= m; ++ i ) {
    		eset[i].uu = rint (), eset[i].vv = rint ();
    		eset[i].ww = rint ();
    	}
    	std::sort ( eset + 1, eset + m + 1 );
    	for ( int i = 1, cnt = 0; i <= m; ++ i ) {
    		if ( unite ( eset[i].uu, eset[i].vv ) ) {
    			inmst[i] = true;
    			link ( eset[i].uu, eset[i].vv, eset[i].ww );
    			link ( eset[i].vv, eset[i].uu, eset[i].ww );
    			if ( ++ cnt == n - 1 ) break;
    		}
    	}
    	DFS ( 1 ), init ();
    	long long ans = 0; int limited = 0;
    	for ( int i = m1 + 1; i <= m; ++ i ) {
    		if ( inmst[i] ) continue;
    		int u = find ( eset[i].uu ), v = find ( eset[i].vv ), w = eset[i].ww;
    		while ( u ^ v ) {
    			if ( dep[u] < dep[v] ) u ^= v ^= u ^= v;
    			if ( ! trc[u] ) ans += w, ++ limited;
    			int t = find ( trf[u] );
    			unite ( u, t ), u = t;
    		}
    	}
    	printf ( "%lld\n", limited == m1 ? ans : -1 );
    	return 0;
    }
    
  • 相关阅读:
    matlab的两种函数简单使用介绍
    有关水晶易表的使用
    有关navicat11版本的破解
    关于配置javaee过程中的问题
    svn在服务器配置安装过程中的问题
    数据挖掘一
    javaee版eclipse导包出现未找到类问题
    git常用命名行总结
    学习kafka的基本信息总结
    JQuery之事件冒泡
  • 原文地址:https://www.cnblogs.com/rainybunny/p/13402438.html
Copyright © 2011-2022 走看看