當年我做這道題時還太嫩了,只能想到暴力。其實如果會了更高的科技這道題只要稍微對暴力優化一下就能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 是 ...