CSP2019 樹的重心(樹的重心 倍增 換根)

2022-05-11 15:34:25 字數 1372 閱讀 6643

當年我做這道題時還太嫩了,只能想到暴力。其實如果會了更高的科技這道題只要稍微對暴力優化一下就能ac(我也不會含淚75pts了)。

廢話不說了,暴力的思路就是列舉每一條邊然後求兩個子樹的重心。

直接求重心的複雜度是\(o(n)\)的,我們考慮優化到\(o(\log)\)。

我們想要求以\(x\)為根的子樹的重心,首先有個引理:這個重心一定在以\(x\)開頭的這條重鏈上(這裡就是輕重鏈剖分中的重鏈)。這是在做這題時想到的。

這其實蠻好理解的,如果\(x\)不是重心,則只有其重兒子才有可能是重心,同理只有其重兒子的重兒子才有可能是重心,所以重心一定在重鏈上。

重心一定有且最多有兩個,所以我們在重鏈上找乙個最深的點\(y\)使得\(n-sz[y] \le \frac\),這個點有可能成為重心。

重心的另乙個性質是如果兩點是重心則其一定相連。這樣我們只需判斷\(y\)和\(father[y]\)是不是中心即可。

怎麼找到\(y\)?我們發現在重鏈上倍增就行,類似倍增求lca。

怎麼維護眾多陣列?換根就行。

關於樹的重心的更多性質

#include #include using namespace std;

typedef long long ll;

const int n = 300000;

template void read(t &x)

template void write(t x)

template void print(t x)

struct nodeedge[n << 1];

int head[n], tot;

int t;

int n;

int sz[n], son[n], g[n][21], father[n];

ll ans;

void init()

void add(int u, int v) ;

head[u] = tot;

}void calc(int x)

void dfs1(int x, int fa)

calc(x);

}int check(int x, int total)

void get_ans(int x)

void change_root(int x, int y)

calc(x);

} if (sz[x] > sz[son[y]]) son[y] = x, calc(y);

}void dfs2(int x, int fa)

}int main()

dfs1(1, 0);

dfs2(1, 0);

print(ans);

} return 0;

}

CSP2019樹的重心

題解 csp2019d2t3 首先我們要明確乙個性質,那就是對於一棵樹的任何乙個節點來說,如果這個點不是重心,那麼這棵樹的重心就一定在這個節點的以重兒子為根節點的子樹裡 證明顯而易見,因為該點不是重心所以siz 重兒子 一定大於 lfloor frac rfloor 另外還有乙個重心的定義 重心所有...

CSP2019 樹的重心

點這裡看題目。原來資料的奇怪結尾就可以拿來判斷特徵呀 太簡單就不說了。考慮完全二叉樹怎麼做。這裡需要注意一點,就是 n 262143 2 1 也就是說,資料實際上就是一棵滿二叉樹。由於滿二叉樹具有極強的對稱性,我們不難想到這樣解決 首先,答案一定包含 frac rt 其中 rt 是樹的根。考慮根的左...

CSP2019 樹的重心 解題報告

csp2019 樹的重心 t 組資料 1 le t le 5 每次給定一棵 n 個點的樹 1 le n le 299995 設 e 為樹的邊集,v x,v y 分別為刪去邊 x,y 後 點 x 所在的點集和點 y 所在的點集.求 sum left sum x 是 v x 的重心 x sum y 是 ...