[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)
[LOJ 6042]「雅禮集訓(xùn) 2017 Day7」跳蚤王國(guó)的宰相
description
solution
一個(gè)到所有節(jié)點(diǎn)距離和最小的節(jié)點(diǎn) ?\Leftrightarrow? 樹(shù)的重心(滿足最重的兒子最輕,每個(gè)兒子siz≤n2\le\frac{n}{2}≤2n?)
顯然原樹(shù)的重心答案為0
對(duì)于點(diǎn)iii,若要成為新的重心
貪心地有,從原重心的最大兒子邊開(kāi)始斷,然后直接接在iii上
此時(shí)把iii提起來(lái)當(dāng)根,則有原來(lái)的子樹(shù)仍不變,斷掉的若干個(gè)子樹(shù)接在下面,剩下的所有點(diǎn)為一個(gè)子樹(shù)
如果原重心斷的子樹(shù)節(jié)點(diǎn)達(dá)到/超過(guò)n2\frac{n}{2}2n?,則一定是可以使任意一個(gè)iii成為新重心的(剩下節(jié)點(diǎn)數(shù)不到一半,符合重心設(shè)定)
最后的答案一定是cnt/cnt?1,cntcnt/cnt-1,cntcnt/cnt?1,cnt表示重心斷的子樹(shù)個(gè)數(shù)
1的出入是因?yàn)橛行c(diǎn)可能自己的sizsizsiz足夠大,不需要斷這么多
如圖:紅邊,黃邊為被斷子樹(shù)(黃邊為最后一個(gè)被斷子樹(shù))
-
iii屬于被斷子樹(shù)內(nèi)(第一個(gè)紅點(diǎn))
先不斷這個(gè)子樹(shù),斷另外的cnt-1個(gè)子樹(shù),此時(shí)需要判斷總點(diǎn)數(shù)n?n-n?其子樹(shù)siz[i]?siz[i]-siz[i]?斷掉的子樹(shù)used=used=used=剩下的子樹(shù)是否>n2>\frac{n}{2}>2n?,超過(guò)再斷iii所在rootrootroot的子樹(shù)
-
iii屬于殘留子樹(shù)(第二個(gè)紅點(diǎn))
先不斷第cnt被斷子樹(shù)(這樣剩下連在一起的子樹(shù)節(jié)點(diǎn)才最小,才更有可能少斷一條邊),同樣的判斷
code
#include <cstdio> #include <vector> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000005 vector < int > G[maxn]; int n, rt, minn, cnt; int siz[maxn], ans[maxn];void dfs( int u, int fa ) {siz[u] = 1;int max_size = 0;for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;else dfs( v, u );siz[u] += siz[v];max_size = max( max_size, siz[v] );}max_size = max( max_size, n - siz[u] );if( max_size < minn ) {minn = max_size;rt = u;} } int GetRoot() {minn = 0x7f7f7f7f;dfs( 1, 0 );return rt; }bool cmp( const int x, const int y ) {return siz[x] > siz[y]; }void solve( int u, int fa, int used ) {ans[u] = cnt + ( ( ( n - siz[u] - used ) << 1 ) > n );for( int i = 0;i < G[u].size();i ++ ) {int v = G[u][i];if( v == fa ) continue;else solve( v, u, used );} }int main() {scanf( "%d", &n );for( int i = 1, u, v;i < n;i ++ ) {scanf( "%d %d", &u, &v );G[u].push_back( v );G[v].push_back( u );}int root = GetRoot();dfs( root, 0 );sort( G[root].begin(), G[root].end(), cmp );int tot = 0;for( int i = 0;i < G[root].size();i ++ ) {tot += siz[G[root][i]];if( ( tot << 1 ) >= n ) break;cnt ++;}for( int i = 0;i < G[root].size();i ++ )solve( G[root][i], root, tot - max( siz[G[root][i]], siz[G[root][cnt]] ) );for( int i = 1;i <= n;i ++ )printf( "%d\n", ans[i] );return 0; }總結(jié)
以上是生活随笔為你收集整理的[LOJ 6042]「雅礼集训 2017 Day7」跳蚤王国的宰相(树的重心+贪心)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 怎样安装声卡驱动 怎样安装声卡驱动教程
- 下一篇: [LOJ #521]「LibreOJ β