JZOJ 1967.【2011集訓隊出題】聰聰可可
阿新 • • 發佈:2020-07-31
題目
思路
看看做做 陰陽 這道題
極力推薦
自從做了這道題後,這些題就變成秒切的題了
很容易想到求節點到分治中心的距離,然後 \(\bmod 3\)
那麼在求根節點一棵子樹的答案時直接加上 \(dis[(3-x) mod 3]\) 的個數
用個桶 \(buc\) 來記錄,若當前節點的 \(dis \bmod 3\) 後結果為 \(0\),說明它到跟也為合法路徑,此時 \(res\) 要額外 \(+1\)
統計完一個子樹的貢獻後再將子樹的資訊加入桶中
統計完所有子樹,重新選根前再 \(dfs\) 一遍清除 \(buc\)
\(Code\)
#include<cstdio> #include<iostream> using namespace std; const int N = 2e4 + 5; int n , h[N] , tot , size , siz[N] , son[N] , dis[N] , use[N] , ans , rt , buc[5]; struct edge{ int to , nxt , w; }e[N * 2]; inline void add(int x , int y , int z) { e[++tot].to = y; e[tot].w = z; e[tot].nxt = h[x]; h[x] = tot; } inline void getrt(int x , int fa) { son[x] = 0 , siz[x] = 1; for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || use[v]) continue; getrt(v , x); siz[x] += siz[v]; son[x] = max(son[x] , siz[v]); } son[x] = max(son[x] , size - siz[x]); rt = son[x] < son[rt] ? x : rt; } inline void getdis(int x , int fa) { for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || use[v]) continue; dis[v] = (dis[x] + e[i].w) % 3; getdis(v , x); } } inline int dfs(int x , int fa) { int res = 0; res += buc[(3 - dis[x]) % 3] + (dis[x] == 0 ? 1 : 0); for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || use[v]) continue; res += dfs(v , x); } return res; } inline void fill(int x , int fa) { buc[dis[x]]++; for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || use[v]) continue; fill(v , x); } } inline void clear(int x , int fa) { buc[dis[x]]--; for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (v == fa || use[v]) continue; clear(v , x); } dis[x] = 0; } inline int calc(int x) { dis[x] = 0; getdis(x , 0); int res = 0; for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (use[v]) continue; res += dfs(v , x) , fill(v , x); } for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (use[v]) continue; clear(v , x); } return res; } inline void divide(int x) { use[x] = 1 , ans += calc(x); for(register int i = h[x]; i; i = e[i].nxt) { int v = e[i].to; if (use[v]) continue; size = siz[v] , rt = 0; getrt(v , x) , divide(rt); } } inline int gcd(int a , int b){return b == 0 ? a : gcd(b , a % b);} int main() { scanf("%d" , &n); int u , v , w; for(register int i = 1; i < n; i++) { scanf("%d%d%d" , &u , &v , &w); add(u , v , w) , add(v , u , w); } son[0] = 2e9 , size = n , rt = 0; getrt(1 , 0) , divide(rt); ans = ans * 2 + n; int tmp = n * n , d = gcd(ans , tmp); printf("%d/%d" , ans / d , tmp / d); }