P2634 [国家集训队]聪聪可可

淀粉质

第二道点分治的题

关于点分治的一点理解:

所谓点分治,其实就是把要求的问题(一般与路径有关)划分成两种情况

1.路径经过rt(根节点)

2.路径在根节点的子树内

我们只需要处理情况1,因为情况2就是情况1的递归子问题

在这个过程中,要注意容斥原理的应用;

//--------------------------------------------------------------------------

关于此题:

w可预先%3(不会影响答案),注意乘法原理的应用;

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<iostream>
  6 using namespace std;
  7 #define up(i,l,r) for(register int i = (l); i <= (r); ++i)
  8 #define dn(i,l,r) for(register int i = (l); i >= (r); --i)
  9 #define ll long long
 10 #define re register
 11 using namespace std;
 12 
 13 template <typename T> void in(T &x) {
 14     x = 0; T f = 1; char ch = getchar();
 15     while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
 16     while( isdigit(ch)) {x = 10 * x + ch - 48; ch = getchar();}
 17     x *= f;
 18 }
 19 
 20 template <typename T> void out(T x) {
 21     if(x < 0) x = -x , putchar('-');
 22     if(x > 9) out(x/10);
 23     putchar(x%10 + 48);
 24 }
 25 //---------------------------------------------------------
 26 
 27 const int N = 20007;
 28 
 29 int n;
 30 ll ans = 0;
 31 
 32 struct edge {
 33     int v,w,nxt;
 34 }e[N<<1];int tot,head[N];
 35 
 36 void add(int u,int v,int w) {
 37     e[++tot].v = v;
 38     e[tot].w = w;
 39     e[tot].nxt = head[u];
 40     head[u] = tot;
 41 }
 42 
 43 //---------------------------------------------------------
 44 
 45 bool vis[N];
 46 int size[N],f[N];
 47 int Tsize,rt,dis[N];
 48 int t[3];
 49 
 50 void get_rt(int u,int fa) {
 51     size[u] = 1; f[u] = 0;
 52     for(re int i = head[u]; i ;i = e[i].nxt) {
 53         int v = e[i].v; if(v == fa || vis[v]) continue;
 54         get_rt(v,u); size[u] += size[v];
 55         f[u] = max(f[u],size[v]);
 56     }
 57     f[u] = max(f[u],Tsize-size[u]);
 58     if(f[u] < f[rt]) rt = u;
 59 }
 60 
 61 void get_dis(int u,int fa) {
 62     ++t[dis[u]%3];
 63     for(re int i = head[u]; i ;i = e[i].nxt) {
 64         int v = e[i].v; if(v == fa || vis[v]) continue;
 65         dis[v] = (dis[u]+e[i].w)%3; get_dis(v,u);
 66     }
 67 }
 68 
 69 ll calc(int u) {
 70     t[0] = t[1] = t[2] = 0;
 71     get_dis(u,0);
 72     return t[0]*t[0]+2*t[1]*t[2];
 73 }
 74 
 75 void solve(int u) {
 76     vis[u] = 1; dis[u] = 0;
 77     ans += calc(u);
 78     for(re int i = head[u]; i ;i = e[i].nxt) {
 79         int v = e[i].v; if(vis[v]) continue;
 80         dis[v] = e[i].w;
 81         ans -= calc(v);
 82         Tsize = size[v],rt = 0,f[0] = n+1;
 83         get_rt(v,0); solve(rt);
 84     }
 85 }
 86 
 87 void init() {
 88     memset(head,0,sizeof(head));
 89     memset(vis,0,sizeof(vis));
 90     ans = 0; Tsize = n,rt = 0,f[0] = n+1;
 91 }
 92 
 93 ll Gcd(ll a,ll b) {return b == 0 ? a:Gcd(b,a%b);}
 94 
 95 int main() {
 96     init();
 97     in(n); int x,y,w;
 98     up(i,1,n-1) {
 99         in(x); in(y); in(w); add(x,y,w%3),add(y,x,w%3);
100         //技巧 mod 3 
101     }
102     get_rt(1,0); solve(rt);
103     ll gcd = Gcd(ans,1ll*n*n);
104     out(ans/gcd); putchar('/'); out(1ll*n*n/gcd);
105     return 0;
106 }

 

posted @ 2019-04-19 18:07  陈星卿  阅读(90)  评论(0编辑  收藏  举报