• [十二省联考2019]春节十二响


    题目

    点这里看题目。

    分析

    感觉自己好蠢

    假如我们有两棵树(T_1,T_2),我们应该怎么计算出它们合并之后的最优解呢?

    设最优情况下,(T_1)的所有内存段的集合为(M_1)(T_2)的集合为(M_2)。我们可以知道,(M_1,M_2)中所有的元素都是不能再合并的(废话)。

    考虑有(m_1,m_2in M_1,m_1>m_2),有(m_3,m_4in M_2, m_3>m_4),我们应该如何分配?我们只能:

    1.最大值和次大值组合,得到的内存为(max{m_1,m_4}+max{m_2,m_4})

    2.最大值和最大值组合,次大值和次大值组合,得到的内存为(max{m_1,m_3}+max{m_2,m_4})

    很显然,方案 2 更优,可以通过枚举所有情况证明

    于是我们就可以想到,用堆维护(M_1)(M_2)。每次取出两个集合中的最大值,合并起来,放到合并结果的堆里面。最后有剩余的,直接塞进新的堆里面。

    很不幸,这样做是(O(sum_u d_u imes log_2n))的,我觉得会 TLE ,其中(d_u)(u)的深度。

    考虑优化。我们每次其实只需要合并,得到合并过后的堆就好。因此,我们可以直接将较小的堆合并到较大的里面,然后就得到了合并结果。这就是启发式合并

    这样做的时间复杂度(O(nlog_2n))我怎么觉得挺像(O(nlog_2^2n))的?

    代码

    #include <queue>
    #include <cstdio>
    using namespace std;
    
    typedef long long LL;
    
    const int MAXN = 2e5 + 5;
    
    template<typename _T>
    void read( _T &x )
    {
    	x = 0;char s = getchar();int f = 1;
    	while( s > '9' || s < '0' ){if( s == '-' ) f = -1; s = getchar();}
    	while( s >= '0' && s <= '9' ){x = ( x << 3 ) + ( x << 1 ) + ( s - '0' ), s = getchar();}
    	x *= f;
    }
    
    template<typename _T>
    void write( _T x )
    {
    	if( x < 0 ){ putchar( '-' ); x = ( ~ x ) + 1; }
    	if( 9 < x ){ write( x / 10 ); }
    	putchar( x % 10 + '0' );
    }
    
    template<typename _T>
    void swapp( _T &x, _T &y )
    {
    	_T t = x; x = y, y = t;
    }
    
    template<typename _T>
    _T MAX( const _T a, const _T b )
    {
    	return a > b ? a : b;
    }
    
    struct edge
    {
    	int to, nxt;
    }Graph[MAXN << 1];
    
    priority_queue<int> q[MAXN];
    
    int stk[MAXN], top;
    int head[MAXN], M[MAXN], id[MAXN];
    int N, cnt;
    
    void addEdge( const int from, const int to )
    {
    	Graph[++ cnt].to = to, Graph[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    
    int merg( int x, int y )
    {
    	if( q[x].size() < q[y].size() ) swapp( x, y );
    	while( ! q[y].empty() ) 
    		stk[++ top] = MAX( q[x].top(), q[y].top() ), 
    		q[x].pop(), q[y].pop();
    	while( top ) q[x].push( stk[top --] );
    	return x; 
    }
    
    void DFS( const int u )
    {
    	id[u] = u;
    	for( int i = head[u], v ; i ; i = Graph[i].nxt )
    	{
    		DFS( v = Graph[i].to ); 
    		id[u] = merg( id[u], id[v] );
    	}
    	q[id[u]].push( M[u] );
    }
    
    int main()
    {
    	read( N );
    	for( int i = 1 ; i <= N ; i ++ ) read( M[i] );
    	for( int i = 2, f ; i <= N ; i ++ ) read( f ), addEdge( f, i );
    	DFS( 1 );
    	LL ans = 0; 
    	while( ! q[id[1]].empty() ) ans += q[id[1]].top(), q[id[1]].pop();
    	write( ans ), putchar( '
    ' );
    	return 0;
    }
    
  • 相关阅读:
    MySQL主从复制
    高可用系列之Nginx
    02.PHP7.x编译详解
    01.PHP5.x编译详解
    月薪2500到年薪20+我经历了些什么?
    更换gitlab公网IP,引发的故障。
    博客资料汇总
    Nginx编译参数
    Zabbix3.0部署最佳实践
    SharePoint 2013让页面显示错误
  • 原文地址:https://www.cnblogs.com/crashed/p/13131219.html
Copyright © 2020-2023  润新知