問題の--single(副走査+数学)へのソリューション

問題の--single(副走査+数学)へのソリューション

数学、あなたは副走査の最適化を使用することができます


フェイス質問

説明
タイトル顔が隠れて

入力
ツリー+ 10,11スタッフラバの束

出力
最小のコストを表す整数

in.1
2
1 2
17 31
2
1 2
0
31 17

out.1
31 17
17 31

データ範囲と表記

データの100%に、T = 5、2 <= N <= 100000,1 <= U、V <= N、 N-1エッジ所与のツリーの形成を保証するために
、100%のデータを、T = 0または、T = 1,1 <= [I [i]は<= 10 ^ 9、Tは= B <= 100,1 <= B保証を指定された配列は、ユニークなアレイ1に相当します。
データの100%が、1つの入力ファイルを使用すると、時間を実行しているプログラムの入力と出力の影響を考慮する必要はありませんが、これらの言葉は次のように理解することができ、200万の以上の整数が含まれていません。
データの100%、回答がintを表すことができる範囲を超えないことを保証するために

考え

主なアイデア

10.プラクティス
のDFS、DEP []アレイを処理の深さ一度各点について。そして、各点の暴力の統計への貢献、N ^ 2複雑さのために

30回のプラクティス
導き出す:進行中のDFS、及び各点はそうする必要がない場合我々は明らかに見出され、それはO(N)の複雑で処理良い副走査ことができます。FAは、Vに転送される場合、具体的に、実際のFA対応するサブツリー部(Vの除去された部分)は、Σの寄与が増加している、及びvサブツリーは、部分的に寄与Σが低減されます。
b[ v ] = b[ fa ] + tot - sum[ v ]*2(SUMは、[] [i]は、Σサブツリーを表します)

60分の練習
と見られるように、アレイは、B既知の場合に、N-1クラスは、式を挙げられ、次いでN ^ 3ガウスの消去法で行う推定。

100の実践
辺の長さに注意が1であり、B [ルート] =Σの和[i]は、 各点のちょうど寄与が再計算されるように。そして、アイデアの同様の違い。
∑( b[ u ] - b[ fa ] )+ 2*b[ root ] = tot*( n-1 )

最後に、還元によって以前溶液アウトのような[1]の処理、。

ディテール

OIerとして、特に、人々のためにLiu_rundaを尊重の話題を維持します

各B [i]は整数1〜1E9として、ブローダイINT以上の数で。(従来法被験者サブカードliu_runda、無敗)

#include<bits/stdc++.h>
using namespace std; 
const int MAXN = 100005 ; 
inline int read(){
    int s=0 ; char g=getchar() ; while(g>'9'||g<'0')g=getchar() ;
    while( g>='0'&&g<='9')s=s*10+g-'0',g=getchar() ;return s ; 
}
int head[ MAXN ] , to[ MAXN*2 ] , nex[ MAXN*2 ] , dep[ MAXN ] , tot = 1 , fa[ MAXN ] , sum[ MAXN ] , du[ MAXN ];
int N , T  , a[ MAXN ] , b[ MAXN ] , root , size[ MAXN ] ;
long long totnum = 0 ;
void  add( int x , int y ){
    to[ ++tot ] = y , nex[ tot ] = head[ x ] , head[ x ] = tot ;
} 
// part a
void  dfs( int u , int  father ){
    fa[ u ] = father ;
    sum[ u ] = a[ u ] ;
    for( int i = head[ u ] ; i ; i = nex[ i ] ){
        if( to[ i ] == father )continue ;
        dep[ to[i] ] = dep[ u ] + 1 ; 
        dfs( to[ i ] , u ) ;
        sum[ u ] += sum[ to[i] ] ;
    }
}
void  dfs2( int  u , int  father ){
    for( int i = head[ u ] ; i ; i = nex[ i ] ){
        if( to[ i ] == father )continue ;
        b[ to[ i ] ] = b[ u ] + sum[ 1 ] - 2*sum[ to[i] ] ;
        dfs2( to[ i ] , u ) ;
    }
}
// part b 
void  dfs3( int u , int father ){
    for( int i = head[ u ] ; i ; i= nex[ i ] ){
        if( to[ i ] == father )continue ; 
        dfs3( to[ i ] , u ) ;
        totnum += ( b[ u ] - b[ to[i] ] ) ;//累计差分
    }
}

void  dfs4( int u , int father ){
    long long tot = 0;
    for(int i = head[ u ] ; i ; i = nex[ i ] ){
        if( father == to[ i ] ) continue;
        size[ to[i] ] = ( b[ u ] - b[ to[ i ] ] + totnum ) / 2 ; 
        tot += size[ to[i] ] ;
        dfs4( to[ i ] , u ) ;
    }
    a[ u ] = size[ u ] - tot ;
} 
void  get_ab(){
    for( int i = 1 ; i <= N ; ++i )a[ i ] = read() ; 
    dfs( 1 , 1 ) ;
    for( int i = 1 ; i <= N ; ++i )b[ 1 ] += dep[ i ]*a[ i ] ;
    dfs2( 1 , 1 ) ;
    for( int i = 1 ; i <= N ; ++i )printf("%d ",b[ i ] );printf("\n") ;
}
void  get_ba(){
    for( int i = 1 ; i <= N ; ++i )b[ i ] = read() ;
    dfs3( 1 , 1 ) ;
    totnum =( b[ 1 ]*2 - totnum ) / ( N-1 ) ;
    dfs4( 1 , 1 ) ;
    for( int i = 2 ; i <= N ; ++i )totnum -= a[ i ] ; printf("%d ",totnum ) ;
    for( int i = 2 ; i <= N ; ++i )printf("%d ", a[ i ] ) ;
    printf("\n");
}
void  clear(){//实际上没必要清那么多
    for( int i = 1 ; i <= N ; ++i )size[ i ] = du[ i ] = sum[ i ] = dep[ i ] = head[ i ] = 0 ;
    tot = 1 , b[ 1 ] = 0 , totnum = 0 ;
}
int main(){
    freopen("single.in","r",stdin);
    freopen("single.out","w",stdout);
    T = read() ; 
    while( T-- ){
        N = read() ; int m1 , m2 ; 
        for( int i = 1 ; i < N ; ++i ){
            m1 = read() , m2 = read() ; add( m1 , m2 ) , add( m2 , m1 ) ;
            du[ m1 ]++ , du[ m2 ]++ ;
        }
        m1 = read() ; 
        if( !m1 )get_ab();
        else get_ba();
        clear() ;
    }
    return 0 ;
}

不十分な場合は、ギャングを明記してください

おすすめ

転載: www.cnblogs.com/ssw02/p/11426124.html