• luogu P2634 [国家集训队]聪聪可可 点分治


    忽然感慨,现在可以随便用__gcd这种函数了。

    点分治一下就好了,最开始点分治的时候忘记选重心,T了一发。

    考虑对于当前点,所有其他点到当前的路径,长为0的t[0]个,长为1的t[1]个,长为2的t[2]个。(取模后长度)那么我们对于一个点x来说,经过他的路径的总数为t[0]*t[0] + t[1] * t[2] * 2。这里t[0]和t[0]相乘,其某个长为0的路径和其本身组合产生一个合法路径,可以看作是,点x为终点的路径。但是有一个其他问题,可能存在两条源于x同一个孩子y的路径产生了组合,这种组合是非法的,我们要想办法删掉这些组合的数量。我们考虑x和y之间长度为v。那么我们只要减掉calc(y,v)即可。即经过y点,长度为v的路径组合后的数量。两个到y的边,各长度为v,正好对应我们之前错误经过x,来回的两个v。calc(y,v)和刚刚的非法组合的数量是相同的。

     1 #include <cstdio>
     2 #include <algorithm>
     3 using namespace std;
     4 const int MAXN = 21000,inf = 100000000;
     5 typedef long long ll;
     6 bool vis[MAXN];
     7 int head[MAXN],siz[MAXN],to[MAXN * 2],nxt[MAXN * 2],val[MAXN * 2];
     8 int n,cnt,root,sum,mx,t[3];
     9 ll ans;
    10 void add(int x,int y,int v)
    11 {
    12     nxt[++cnt] = head[x];
    13     to[cnt] =y;
    14     head[x] = cnt;
    15     val[cnt] = v;
    16 }
    17 void get_root(int x,int frm)
    18 {
    19     siz[x] = 1;
    20     int tmx = 0;
    21     for (int i = head[x];i;i = nxt[i])
    22     {
    23         if (to[i] == frm || vis[to[i]] == true)
    24             continue;
    25         get_root(to[i],x);
    26         siz[x] += siz[to[i]];
    27         tmx = max(tmx,siz[to[i]]);
    28     }
    29     tmx = max(tmx,sum - siz[x]);
    30     if (tmx < mx) root = x,mx = tmx;
    31 }
    32 void get_dis(int x,int frm,int mod)
    33 {
    34     t[mod]++;
    35     for (int i = head[x];i;i = nxt[i])
    36     {
    37         if (to[i] == frm || vis[to[i]] == true)
    38             continue;
    39         get_dis(to[i],x,(mod + val[i]) % 3);
    40     }
    41 }
    42 ll calc(int x,int mod)
    43 {
    44     t[0] = t[1] = t[2] = 0;
    45     get_dis(x,0,mod);
    46     return (ll)t[0] * t[0] + (ll)t[1] * t[2] * 2; 
    47 }
    48 void pot_div(int x)
    49 {
    50     ans += calc(x,0);
    51     vis[x] = true;
    52     for (int i = head[x];i;i = nxt[i])
    53     {
    54         if (vis[to[i]] == true) continue;
    55         ans -= calc(to[i],val[i]);
    56         mx = inf;
    57         sum = siz[to[i]];
    58         get_root(to[i],0);
    59         pot_div(root);
    60     }
    61 }
    62 int main()
    63 {
    64     scanf("%d",&n);
    65     int tx,ty,tv;
    66     for (int i = 1;i <= n - 1;i++)
    67     {
    68         scanf("%d%d%d",&tx,&ty,&tv);
    69         add(tx,ty,tv % 3);
    70         add(ty,tx,tv % 3);
    71     }
    72     mx = inf;
    73     sum = n;
    74     get_root(1,0);
    75     pot_div(root);
    76     ll tot = (ll)n * n;
    77     ll g = __gcd(tot,ans);
    78     printf("%lld/%lld
    ",ans / g,tot / g);
    79     return 0;
    80 }
    心之所动 且就随缘去吧
  • 相关阅读:
    如果你的领导是力量型,你在汇报工作时应该注意()。
    项目管理的10项原则
    扑克k,你知道的人物吗?
    搭建属于您自己的软件版本控制
    Android保持屏幕常亮的方法
    BMP图像数据格式详解
    Android终止线程的方法
    使用ContentProvider访问其他应用的SharedPreferences数据
    android gps定位LocationManager
    Android属性之build.prop生成过程分析
  • 原文地址:https://www.cnblogs.com/iat14/p/10524358.html
Copyright © 2020-2023  润新知