zoukankan      html  css  js  c++  java
  • 「HNOI2014」世界树

    题目链接

    问题分析

    首先观察数据范围可以知道要用虚树。但是要考虑怎么维护原树的距离信息。

    如果只有两个关键点,我们可以很方便地找到中点将整棵树划分为两部分。而如果有多个关键点,看起来有效的方法就是多源的BFS。而虚树上边的长度不相同,分割点又不一定在虚树上,所以这个方法并不那么适用。

    考虑到虚树实际上维护了所有关键点和LCA之间的关系。这样一来,虚树上相邻的两个点一定是原树上祖先与后代的关系。而且这条链上所挂的其他子树里面没有关键点。这样一来,对于这一条链,如果我们知道了两个端点分别属于哪个关键点,那么我们可以简单的通过原树上子树的size加减来求得答案。所以我们得到了这样的做法:

    在虚树上跑两遍DP,求出虚树上每个点最近的关键点位置及其距离。

    为了较为良好地处理边界问题,我们这样统计答案:

    对于一个点,我们首先假设 原树中以这个点为根的子树上的点 都属于 这个点属于的关键点。然后遍历它的儿子。对于每个儿子,找到分界点,然后减去不属于当前点的位置(通过在原树上的深度计算,然后倍增确定位置)。注意这里的链并不包括当前点和它的儿子。这样遍历完整棵虚树就可以得到答案了。

    参考程序

    loj不加读入优化,不加奇怪模板中最长代码

    #include <bits/stdc++.h>
    //#define Debug
    using namespace std;
    
    const int Maxn = 300010;
    const int MaxLog = 20;
    const int INF = 100000010;
    struct edge {
    	int To, Next;
    	edge() {}
    	edge( int _To, int _Next ) : To( _To ), Next( _Next ) {}
    };
    struct tree {
    	int Start[ Maxn ], Used, Flag[ Maxn ], State;
    	edge Edge[ Maxn << 1 ];
    	tree() {
    		State = Used = 0;
    		memset( Flag, 255, sizeof( Flag ) );
    		return;
    	}
    	inline void Set( int _State ) {
    		Used = 0; State = _State;
    		return;
    	}
    	inline void AddDirectedEdge( int x, int y ) {
    		if( Flag[ x ] != State ) {
    			Flag[ x ] = State;
    			Start[ x ] = 0;
    		}
    		Edge[ ++Used ] = edge( y, Start[ x ] );
    		Start[ x ] = Used;
    		return;
    	}
    	inline void AddUndirectedEdge( int x, int y ) {
    #ifdef Debug 
    		printf( "AddEdge %d %d
    ", x, y );
    #endif
    		AddDirectedEdge( x, y );
    		AddDirectedEdge( y, x );
    	}
    };
    
    namespace MainTree {
    	tree Tree;
    	int n, Deep[ Maxn ], D[ Maxn ][ MaxLog ], Dfn[ Maxn ], Time, Size[ Maxn ];
    	void Build( int u, int Fa ) {
    		Size[ u ] = 1;
    		D[ u ][ 0 ] = Fa;
    		Dfn[ u ] = ++Time;
    		Deep[ u ] = Deep[ Fa ] + 1;
    		for( int i = 1; i < MaxLog; ++i ) 
    			D[ u ][ i ] = D[ D[ u ][ i - 1 ] ][ i - 1 ];
    		for( int t = Tree.Start[ u ]; t; t = Tree.Edge[ t ].Next ) {
    			int v = Tree.Edge[ t ].To;
    			if( v == Fa ) continue;
    			Build( v, u );
    			Size[ u ] += Size[ v ];
    		}
    		return;
    	}
    	void Init() {
    		Tree.Set( 0 );
    		scanf( "%d", &n );
    		for( int i = 1; i < n; ++i ) {
    			int x, y;
    			scanf( "%d%d", &x, &y );
    			Tree.AddUndirectedEdge( x, y );
    		}
    		Build( 1, 0 );
    		return;
    	}
    	int GetLca( int x, int y ) {
    		if( Deep[ x ] < Deep[ y ] ) swap( x, y );
    		for( int i = MaxLog - 1; i >= 0; --i ) 
    			if( Deep[ D[ x ][ i ] ] >= Deep[ y ] )
    				x = D[ x ][ i ];
    		if( x == y ) return x;
    		for( int i = MaxLog - 1; i >= 0; --i )
    			if( D[ x ][ i ] != D[ y ][ i ] ) {
    				x = D[ x ][ i ];
    				y = D[ y ][ i ];
    			}
    		return D[ x ][ 0 ];
    	}
    } //MainTree
    
    namespace VirtualTree {
    	bool Cmp( int x, int y ) {
    		return MainTree::Dfn[ x ] < MainTree::Dfn[ y ];
    	}
    	int m, h[ Maxn ], Important[ Maxn ], Stack[ Maxn ], Flag;
    	int Rec[ Maxn ];
    	tree Tree; 
    	int Ans[ Maxn ], Deg[ Maxn ];
    	void Init( int _Flag ) { 
    		Flag = _Flag;
    		Tree.Set( Flag );
    		scanf( "%d", &m );
    		for( int i = 1; i <= m; ++i ) scanf( "%d", &h[ i ] );
    		for( int i = 1; i <= m; ++i ) Rec[ i ] = h[ i ];
    		sort( h + 1, h + m + 1, Cmp );
    #ifdef Debug 
    		for( int i = 1; i <= m; ++i ) printf( "%d ", Rec[ i ] ); printf( "
    " );
    #endif
    		for( int i = 1; i <= m; ++i ) Important[ h[ i ] ] = Flag;
    		for( int i = 1; i <= m; ++i ) Deg[ i ] = 0;
    		Stack[ 0 ] = Stack[ 1 ] = 1;
    		for( int i = 1; i <= m; ++i ) {
    			if( i == 1 && h[ i ] == 1 ) continue;
    			int Lca = MainTree::GetLca( h[ i ], Stack[ Stack[ 0 ] ] );
    #ifdef Debug
    			printf( "%d %d, Lca = %d
    ", h[ i ], Stack[ Stack[ 0 ] ], Lca );
    #endif
    			if( MainTree::Deep[ Lca ] == MainTree::Deep[ Stack[ Stack[ 0 ] ] ] ) {
    				Stack[ ++Stack[ 0 ] ] = h[ i ];
    			} else {
    				while( MainTree::Deep[ Lca ] < MainTree::Deep[ Stack[ Stack[ 0 ] - 1 ] ] ) {
    					Tree.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
    					++Deg[ Stack[ Stack[ 0 ] - 1 ] ];
    					--Stack[ 0 ];
    				}
    				if( MainTree::Deep[ Lca ] == MainTree::Deep[ Stack[ Stack[ 0 ] - 1 ] ] ) {
    					Tree.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
    					++Deg[ Stack[ Stack[ 0 ] - 1 ] ];
    					--Stack[ 0 ];
    					Stack[ ++Stack[ 0 ] ] = h[ i ];
    				} else {
    					Tree.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Lca );
    					++Deg[ Lca ];
    					--Stack[ 0 ];
    					Stack[ ++Stack[ 0 ] ] = Lca;
    					Stack[ ++Stack[ 0 ] ] = h[ i ];
    				}
    			}
    		}
    		while( Stack[ 0 ] > 1 ) {
    			Tree.AddUndirectedEdge( Stack[ Stack[ 0 ] ], Stack[ Stack[ 0 ] - 1 ] );
    			++Deg[ Stack[ Stack[ 0 ] - 1 ] ];
    			--Stack[ 0 ];
    		}
    		return;
    	}
    	int Belong[ Maxn ], Dis[ Maxn ];
    	void Dfs1( int u, int Fa ) {
    		Belong[ u ] = 0;
    		if( Important[ u ] == Flag ) {
    			Dis[ u ] = 0;
    			Belong[ u ] = u;
    		} else {
    			Dis[ u ] = INF;
    			Belong[ u ] = INF;
    		}
    		for( int t = Tree.Start[ u ]; t; t = Tree.Edge[ t ].Next ) {
    			int v = Tree.Edge[ t ].To;
    			if( v == Fa ) continue;
    			Dfs1( v, u );
    			int T = Dis[ v ] + MainTree::Deep[ v ] - MainTree::Deep[ u ];
    			if( T < Dis[ u ] || ( T == Dis[ u ] && Belong[ v ] < Belong[ u ] ) ) {
    				Dis[ u ] = T;
    				Belong[ u ] = Belong[ v ];
    			}
    		}
    		return;
    	}
    	void Dfs2( int u, int Fa, int _Dis, int _Belong ) {
    		if( _Dis < Dis[ u ] || ( _Dis == Dis[ u ] && _Belong < Belong[ u ] ) ) {
    			Dis[ u ] = _Dis;
    			Belong[ u ] = _Belong;
    		}
    		if( Dis[ u ] < _Dis || ( Dis[ u ] == _Dis && Belong[ u ] < _Belong ) ) {
    			_Dis = Dis[ u ];
    			_Belong = Belong[ u ];
    		}
    		for( int t = Tree.Start[ u ]; t; t = Tree.Edge[ t ].Next ) {
    			int v = Tree.Edge[ t ].To;
    			if( v == Fa ) continue;
    			Dfs2( v, u, _Dis + MainTree::Deep[ v ] - MainTree::Deep[ u ], _Belong );
    		}
    #ifdef Debug 
    		printf( "u = %d, Dis = %d, Belong = %d
    ", u, Dis[ u ], Belong[ u ] );
    #endif
    		return;
    	}
    	void GetMinDis() {
    		Dfs1( 1, 0 );
    		Dfs2( 1, 0, INF, INF );
    		return;
    	}
    	void Cal( int u, int v ) {
    		int MidDeep = ( MainTree::Deep[ u ] - Dis[ u ] + 1
    				+ MainTree::Deep[ v ] + Dis[ v ] - 1 ) / 2;
    		int Dis1 = MidDeep - ( MainTree::Deep[ u ] - Dis[ u ] + 1 );
    		int Dis2 = ( MainTree::Deep[ v ] + Dis[ v ] - 1 ) - MidDeep;
    		if( Dis1 == Dis2 && Belong[ v ] < Belong[ u ] ) --MidDeep;
    		Dis1 = MidDeep - ( MainTree::Deep[ u ] - Dis[ u ] + 1 );
    		Dis2 = ( MainTree::Deep[ v ] + Dis[ v ] - 1 ) - MidDeep;
    		int SpotMid = v;
    		for( int i = MaxLog - 1; i >= 0; --i )
    			if( MainTree::Deep[ MainTree::D[ SpotMid ][ i ] ] > MidDeep )
    				SpotMid = MainTree::D[ SpotMid ][ i ];
    		int SpotTop = v;
    		for( int i = MaxLog - 1; i >= 0; --i )
    			if( MainTree::Deep[ MainTree::D[ SpotTop ][ i ] ] > MainTree::Deep[ u ] )
    				SpotTop = MainTree::D[ SpotTop ][ i ];
    #ifdef Debug 
    		printf( "    Link %d %d
    ", u, v );
    		printf( "    MidDeep = %d, Dis1 = %d, Dis2 = %d
    ", MidDeep, Dis1, Dis2 );
    #endif
    		Ans[ Belong[ u ] ] -= MainTree::Size[ SpotTop ];
    #ifdef Debug 
    		printf( "        %d -= %d, %d = %d
    ", Belong[ u ], MainTree::Size[ SpotTop ], Belong[ u ], Ans[ Belong[ u ] ] );
    #endif
    		Ans[ Belong[ u ] ] += MainTree::Size[ SpotTop ] - MainTree::Size[ SpotMid ];
    #ifdef Debug 
    		printf( "        %d += %d, %d = %d
    ", Belong[ u ], MainTree::Size[ SpotTop ] - MainTree::Size[ SpotMid ], Belong[ u ], Ans[ Belong[ u ] ] );
    #endif
    		Ans[ Belong[ v ] ] += MainTree::Size[ SpotMid ] - MainTree::Size[ v ];
    #ifdef Debug 
    		printf( "        %d += %d, %d = %d
    ", Belong[ v ], MainTree::Size[ SpotMid ] - MainTree::Size[ v ], Belong[ v ], Ans[ Belong[ v ] ] );
    #endif
    		return;
    	}
    	void Dfs3( int u, int Fa ) {
    		Ans[ Belong[ u ] ] += MainTree::Size[ u ];
    #ifdef Debug 
    		printf( "Point %d, %d += %d, %d = %d
    ", u, Belong[ u ], MainTree::Size[ u ], Belong[ u ], Ans[ Belong[ u ] ] );
    #endif
    		for( int t = Tree.Start[ u ]; t; t = Tree.Edge[ t ].Next ) {
    			int v = Tree.Edge[ t ].To;
    			if( v == Fa ) continue;
    			Cal( u, v );
    			Dfs3( v, u );
    		}
    		return;
    	}
    	void Cal() {
    		for( int i = 1; i <= m; ++i ) Ans[ h[ i ] ] = 0;
    		Dfs3( 1, 0 );
    		return;
    	}
    	void Print() {
    		for( int i = 1; i <= m; ++i ) 
    			printf( "%d ", Ans[ Rec[ i ] ] );
    		printf( "
    " );
    		return;
    	}
    } //VirtualTree
    
    void Work( int Flag ) {
    	VirtualTree::Init( Flag );
    	VirtualTree::GetMinDis();
    	VirtualTree::Cal();
    	VirtualTree::Print();
    	return;
    }
    
    int main() {
    	MainTree::Init();
    #ifdef Debug 
    	printf( "***
    " );
    #endif
    	int TestCases;
    	scanf( "%d", &TestCases );
    	for( ; TestCases; --TestCases ) Work( TestCases );
    	return 0;
    }
    
  • 相关阅读:
    SAP 差旅报销集成方案的实现
    SAP DBDI 网银接口实现案例
    SAP Actual Costing with Material Ledger 激活实际成本后台配置
    技能UP:SAP CO掌上配置手册
    技能UP:SAP OBYC自动记账的实例说明(含value String应用说明)
    SAP OBYC自动记账的实例说明 +VALUE STRING
    SAP MM/FI 自动过账实现 OBYC 接口执行
    情商UP:不遵守八小时工作制,你就能富起来??
    SAP中方会计凭证打印解决方案
    二维码推广方法20种
  • 原文地址:https://www.cnblogs.com/chy-2003/p/11611892.html
Copyright © 2011-2022 走看看