質問: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は同じ
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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); for(int i = 1 ; i <= n; i ++ ) scanf(" %lld "、&a [i]); for(int 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 ; for(int i = 1 ; i <= n; i ++ ){ if (a [i]) id [ ++ m] = i; } sort(id + 1、id + 1 + m、cmp1); ll ans = 0 ; for(intfir = 1 ; fir <= m; fir ++ ){ int sec = fir; while(sec <= m && deep [id [fir]] == deep [id [sec]]) sec ++ ; 秒 - ; for(int 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); for(int 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を返し ます。 }