zoukankan      html  css  js  c++  java
  • [国家集训队]聪聪可可

    嘟嘟嘟


    算是一道点分治入门题吧。


    分治的时候,我们只用考虑过重心的路径中边权和是(3)的倍数的路径条数。对于一个节点(i),设他到重心的路径的权值之和(mod 3)(x),则能和他配对的点必须满足(dis_j mod 3 = 3 - x)
    这样做法就很显然了。不过如果把所有子树都跑一遍在统计答案,判断两点是否在同一子树比较麻烦。所以每一个子树遍历完后就统计一边答案。
    代码中我写了三个(dfs)。第一个是求重心的,第二个是统计答案的,第三个是更新距离的。(其实后两个(dfs)长的很像)

    #include<cstdio>
    #include<iostream>
    #include<cmath>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #include<cctype>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    #define enter puts("") 
    #define space putchar(' ')
    #define Mem(a, x) memset(a, x, sizeof(a))
    #define rg register
    typedef long long ll;
    typedef double db;
    const int INF = 0x3f3f3f3f;
    const db eps = 1e-8;
    const int maxn = 2e4 + 5;
    inline ll read()
    {
      ll ans = 0;
      char ch = getchar(), last = ' ';
      while(!isdigit(ch)) last = ch, ch = getchar();
      while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar();
      if(last == '-') ans = -ans;
      return ans;
    }
    inline void write(ll x)
    {
      if(x < 0) x = -x, putchar('-');
      if(x >= 10) write(x / 10);
      putchar(x % 10 + '0');
    }
    
    int n, Siz = 0;
    struct Edge
    {
      int nxt, to, w;
    }e[maxn << 1];
    int head[maxn], ecnt = -1;
    void addEdge(int x, int y, int w)
    {
      e[++ecnt] = (Edge){head[x], y, w};
      head[x] = ecnt;
    }
    
    bool out[maxn];
    int siz[maxn], Max[maxn];
    void dfs1(int now, int _f, int& cg)
    {
      siz[now] = 1; Max[now] = -1;
      for(int i = head[now], v; i != -1; i = e[i].nxt)
        if(!out[v = e[i].to] && v != _f)
          {
    	dfs1(v, now, cg);
    	siz[now] += siz[v];
    	Max[now] = max(Max[now], siz[v]);
          }
      Max[now] = max(Max[now], Siz - siz[now]);
      if(!cg || Max[now] < Max[cg]) cg = now;
    }
    
    ll ans = 0;
    int num[3];
    void dfs2(int now, int _f, int dis)
    {
      ans += num[(3 - dis) % 3];
      for(int i = head[now], v; i != -1; i = e[i].nxt)
        if(!out[v = e[i].to] && v != _f) dfs2(v, now, (dis + e[i].w) % 3);
    }
    void dfs3(int now, int _f, int dis)
    {
      num[dis]++;
      if(!dis) ans++;
      for(int i = head[now], v; i != -1; i = e[i].nxt)
        if(!out[v = e[i].to] && v != _f) dfs3(v, now, (dis + e[i].w) % 3);
    }
    
    void solve(int now)
    {
      int cg = 0;
      dfs1(now, 0, cg); out[cg] = 1;
      num[0] = num[1] = num[2] = 0;
      for(int i = head[cg], v; i != -1; i = e[i].nxt)
        if(!out[v = e[i].to])
          {
    	dfs2(v, 0, e[i].w);
    	dfs3(v, 0, e[i].w);
          }
      for(int i = head[cg], v; i != -1; i = e[i].nxt)
        if(!out[v = e[i].to]) Siz = siz[v], solve(v);
    }
    
    ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
    
    int main()
    {
      Mem(head, -1);
      n = read();
      for(int i = 1; i < n; ++i)
        {
          int x = read(), y = read(), w = read() % 3;
          addEdge(x, y, w); addEdge(y, x, w);
        }
      Siz = n;
      solve(1);
      ans = (ans << 1) + n;
      ll x = n * n;
      ll d = gcd(ans, x);
      write(ans / d), putchar('/'), write(x / d), enter;
      return 0;
    }
    
  • 相关阅读:
    JDK,JRE,JVM,三者,你知道它们的关系么
    Linux防火墙机制
    mysql数据可以连接到myeclipse当中需要知道的语法
    mysql数据库常用命令
    修改mysql默认编码重启后又还原,且在修改my.ini配置文件出现1067错误的解决办法。
    MySQL 5.5 Command Line Client 打开出现闪退(错误)的解决办法
    修改mysql 的初始密码
    linux命令的续行,linux shell 参数换行(标准说法:续行)
    java面试(反射)05
    java面试(进程和线程)04
  • 原文地址:https://www.cnblogs.com/mrclr/p/10033454.html
Copyright © 2011-2022 走看看