聪聪可可(点分治)

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define maxn 40000
using namespace std;
struct eg
{
    int to,v,nxt;
}b[maxn];
int head[maxn],tot=0,f[maxn],sz[maxn],vis[maxn],d[maxn]={0},ans,root,sum,t1[5];
int gcd(int x,int y){return y?gcd(y,x%y):x;}
void link(int x,int y,int z)
{
    b[++tot].nxt=head[x];
    b[tot].to=y;
    b[tot].v=z;
    head[x]=tot;
}
void getroot(int u,int fa)
{
    sz[u]=1,f[u]=0;
    for (int i=head[u];i;i=b[i].nxt)
    {
        int t=b[i].to;
        if (vis[t]||t==fa) continue;
        getroot(t,u);
        sz[u]+=sz[t];
        f[u]=max(f[u],sz[t]);
    }
    f[u]=max(f[u],sum-sz[u]);
    if (f[root]>f[u]) root=u;
}
void getdeep(int x,int fa)
{
    t1[d[x]]++;
    for (int i=head[x];i;i=b[i].nxt)
    {
        int t=b[i].to;
        if (vis[t]||t==fa) continue;
        d[t]=(d[x]+b[i].v)%3;
        getdeep(t,x);
    }
}
int cal(int x,int vv)
{
    d[x]=vv%3;
    t1[0]=t1[1]=t1[2]=0;
    getdeep(x,0);
    return t1[1]*t1[2]*2+t1[0]*t1[0];
}
void work(int x)
{
    ans+=cal(x,0);
    vis[x]=1;
    for (int i=head[x];i;i=b[i].nxt)
    {
        int t=b[i].to;
        if (vis[t]) continue;
        ans-=cal(t,b[i].v);
        sum=sz[t];
        root=0;
        getroot(t,0);
        work(root);
    }
}
int main()
{
    int n;
    scanf ("%d",&n);
    for (int i=1;i<n;++i)
    {
        int x,y,w;
        scanf ("%d%d%d",&x,&y,&w);
        link(x,y,w);
        link(y,x,w);
    }
    root=0;f[0]=n,sum=n;
    getroot(1,0);
    work(root);
    int l=gcd(ans,n*n);
    cout<<(ans/l)<<"/"<<(n*n/l);
    return 0;
}

点分治板子
然而想那个 t1[1]*t1[2]*2+t1[0]*t1[0]想了好久
就是最基本的组合方法 毕竟(2,5)和(5,2)可是要算两次的
画画图就好了
(不要像我一样盯着大佬们的显然可得懵逼23333)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值