G血圧ゲーム(ツリー内の同じ高さのポイントが同時にルートに移動します、lca)

質問:https : //ac.nowcoder.com/acm/contest/5278/G

トピック:nポイントのツリーが指定されている場合、各ノードには重みがあり、各ノードの重みは毎回高さだけ移動します。ノードの重みが1より大きい場合、このノードはこのノードに重みを持ちます値は、ツリーのルートに移動するまで1ずつ減らされ、最終的な重みが回答に追加されます。最後に、この回答の合計は何ですか?

分析:異なる高さでルートに向かって走る過程での重みの組み合わせ(パスの組み合わせ)と軽量化の過程は互いに影響しないことがわかっているため、同じ高さのノードを分割するように促されます。分析する同じ高さのグループ。

   最も複雑なケースは、パスのマージです。各パスのマージは、2つのLCAのマージまたは2つのLCAのマージでなければなりません。、このグループからすべてのlcaを取得する方法を見つける必要がありますか?調べた後、答えを直接シミュレートできるからです。

   そして、同じ高さのノードのすべてのlcaは、各ノードのdfsの順序であり、ソート後の隣接ノードのlcaは、これらのノードが実行するために通過する接合点であるという結論があります。接続点は、この高さノード番号-1を超えません。

   処理するときは、ゼロ以外の点のみを処理する必要があります。2つの隣接ノードx、yからlcaの場合、それらの間に組み合わせはなく、xのlcaへの寄与は、彼の現在の重み-(x lcaの深さとの違い)、yは同じ

#include <bits / stdc ++。h>
 using  namespace std; 
typedef long  long ll;
#define pb push_back
 const  int M = 2e5 + 5 ; 
ベクトル < int > g [M];
int sz [M]、deep [M]、dfn [M]、cnt、f [M]、tp [M]、son [M]、id [M]、fa [M]; 
ll a [M]、val [M]; 
struct node {
     int son1、son2、p; 
} same [M]; 
void dfs1(int u、int ff){ 
    sz [u] = 1、deep [u] = deep [ff] + 1、dfn [u] = ++ cnt、fa [u] = ff;
    for (auto v:g [u]){
         if(v!= ff){ 
            dfs1(v、u); 
            sz [u] + = sz [v];
            if(sz [son [u]] < sz [v])
                son [u] = v; 
        } 
    } 
} 
void dfs2(int u、int top){ 
    tp [u] = top;
    if (son [u])
        dfs2(son [u]、top); 
    for (auto v:g [u]){
         if(v!= fa [u] && v!= son [u])
            dfs2(v、v); 
    } 
} 
int LCA(int x、int y){
     while(tp [x]!= tp [y]){
         if(deep [tp [x]]> deep [tp [y]])
            x = fa [tp [x]];
        それ以外の場合
            y = fa [tp [y]]; 
    }
     deep [x]> deep [y]を返しますか?y:x; 
} 
int find(int x){
     return f [x] == x?x:f [x] = find(f [x]); 
} 
bool cmp1(int x、int y){
     if(deep [x] == deep [y])
         return dfn [x] < dfn [y];
    deep [x]> deep [y];を
返します。
} bool cmp2(node x、node y){
     if(deep [xp] == deep [yp])
         return dfn [xp] < dfn [yp];
    deep [xp]> deep [yp];を返します。
} 
int main(){
     int n、rt; 
    scanf(" %d%d "、&​​n、&rt);
    forint i = 1 ; i <= n; i ++ 
        scanf(" %lld "、&​​a [i]);
    forint u、v、i = 1; i <n; i ++ ){ 
        scanf(" %d%d "、&​​u、&v); 
        g [u] .pb(v); 
        g [v] .pb(u); 
    } 
    dfs1(rt、0 ); 
    dfs2(rt、rt); 
    int m = 0 ;
    forint i = 1 ; i <= n; i ++ ){
         if (a [i])
            id [ ++ m] = i; 
    } 
    sort(id + 1、id + 1 + m、cmp1); 
    ll ans = 0 ;
    forintfir = 1 ; fir <= m; fir ++ ){
         int sec = fir;
        while(sec <= m && deep [id [fir]] == deep [id [sec]])
            sec ++ ;  - ;
        forint i = fir; i <= sec; i ++ 
            f [id [i]] = id [i]、val [id [i]] = a [id [i]];
        if(fir == sec){ 
            ans + = max(1ll、a [id [fir]]- deep [id [fir]]);
            続ける; 
        } 
        int tot = 0 ;
        以下のためのint i = fir; i <sec; i ++ ){
             int lca = LCA(id [i]、id [i + 1 ]); 
            same [ ++ tot] .p = lca; 
            same [tot] .son1 = id [i]; 
            same [tot] .son2 = id [i + 1 ]; 
            f [lca] = lca; 
            val [lca] = 0 ; 
        } 
        sort(same + 1、same + 1 + tot、cmp2);
        forint i = 1 ; i <= tot; i ++ ){
             intx = find(same [i] .son1)、y = find(same [i] .son2); 
            ll val1 = 0、val2 = 0 ;
            if(x!= same [i] .p)
                val1 = max(1ll、val [x]-(deep [x ]-deep [same [i] .p]));
            if(y!= same [i] .p)
                val2 = max(1ll、val [y]-(deep [y ]-deep [same [i] .p])); 
            val [same [i] .p] + = val1 + val2; 
            f [x] = f [y] = same [i] .p; 

        } 
        ans + = max(1ll、val [same [tot] .p]-deep [same [tot] .p]); 
        モミ = 秒;
    } 
    printf(" %lld " 、ans);
    0を返し ます
}
コードを表示

 

おすすめ

転載: www.cnblogs.com/starve/p/12735709.html