2152:聪聪可可(点分治)
分析:
点分治。
代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<iostream> 5 #include<cmath> 6 7 using namespace std; 8 const int INF = 2e9; 9 const int N = 50010; 10 struct Edge{ 11 int to,w,nxt; 12 Edge() {} 13 Edge(int a,int b,int c) {to = a,w = b,nxt = c;} 14 }e[100100]; 15 int f[10],Ans,ans = INF,Sum,tot,Root; 16 int d[N],head[N],son[N]; 17 bool vis[N]; 18 19 inline int read() { 20 int x = 0,f = 1;char ch=getchar(); 21 for (; ch<'0'||ch>'9'; ch=getchar()) if(ch=='-')f=-1; 22 for (; ch>='0'&&ch<='9'; ch=getchar()) x=x*10+ch-'0'; 23 return x*f; 24 } 25 inline void add_edge(int u,int v,int w) { 26 e[++tot] = Edge(v,w,head[u]);head[u] = tot; 27 e[++tot] = Edge(u,w,head[v]);head[v] = tot; 28 } 29 void getroot(int u,int fa) { 30 int cnt = 0;son[u] = 1; 31 for (int i=head[u]; i; i=e[i].nxt) { 32 int v = e[i].to; 33 if (v==fa || vis[v]) continue; 34 getroot(v,u); 35 son[u] += son[v]; 36 cnt = max(cnt,son[v]); 37 } 38 cnt = max(cnt,Sum-son[u]); // son[u]以u为根的子树中,不包含u的所有的节点 39 if (cnt < ans) {ans = cnt;Root = u;} 40 } 41 void getdeep(int u,int fa) { 42 f[d[u]] ++; 43 for (int i=head[u]; i; i=e[i].nxt) { 44 int v = e[i].to; 45 if (v==fa || vis[v]) continue; 46 d[v] = (d[u]+e[i].w)%3; 47 getdeep(v,u); 48 } 49 } 50 int calcc(int x,int w) { 51 d[x] = w % 3; 52 f[0] = f[1] = f[2] = 0; 53 getdeep(x,0); 54 return f[1]*f[2]*2+f[0]*f[0]; 55 } 56 void solve(int u) { 57 Ans += calcc(u,0); 58 vis[u] = true; 59 for (int i=head[u]; i; i=e[i].nxt) { 60 int v = e[i].to; 61 if (vis[v]) continue; 62 Ans -= calcc(v,e[i].w); 63 Sum = son[v];ans = INF; 64 getroot(v,0); 65 solve(Root); 66 } 67 } 68 int gcd(int a,int b) { 69 if (b==0) return a; 70 return gcd(b,a%b); 71 } 72 int main () { 73 int n = read(); 74 for (int i=1; i<n; ++i) { 75 int u = read(),v = read(),w = read(); 76 add_edge(u,v,w%3); 77 } 78 Sum = n; 79 getroot(1,0); 80 solve(Root); 81 if (Ans == 0) { 82 cout << "0/0";return 0; 83 } 84 int a = Ans,b = n*n,c = gcd(a,b); 85 cout << a/c << "/" << b/c; 86 return 0; 87 }