题目链接

题面:

题意:
求树上两点之间距离为3的倍数的点对数量。

代码:

#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<map>
#include<vector>
#define ll long long
#define llu unsigned ll
using namespace std;
const int maxn=41000;
const int inf=0x3f3f3f3f;
int head[maxn],ver[maxn],edge[maxn],nt[maxn];
int max_part[maxn],si[maxn],cnt[3];
bool ha[maxn];
int tot=1,root,max_size,ans=0,n,k;

ll gcd(ll a,ll b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

void add(int x,int y,int z)
{
    ver[++tot]=y,edge[tot]=z;
    nt[tot]=head[x],head[x]=tot;
}

void dfs_size(int x,int fa)
{
    si[x]=1,max_part[x]=0;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(ha[y]||y==fa) continue;
        dfs_size(y,x);
        si[x]+=si[y];
        max_part[x]=max(max_part[x],si[y]);
    }
}

void dfs_root(int now_root,int x,int fa)
{
    max_part[x]=max(max_part[x],si[now_root]-si[x]);

    if(max_size>max_part[x])
    {
        max_size=max_part[x];
        root=x;
    }
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i];
        if(ha[y]||y==fa) continue;
        dfs_root(now_root,y,x);
    }
}

void dfs_dis(int x,int fa,int dis)
{
    cnt[dis]++;
    for(int i=head[x];i;i=nt[i])
    {
        int y=ver[i],z=edge[i];
        if(ha[y]||y==fa) continue;
        dfs_dis(y,x,(dis+z)%3);
    }
}

int get_num(int x,int d)
{
    cnt[0]=cnt[1]=cnt[2]=0;
    dfs_dis(x,-1,d%3);
    return cnt[0]*cnt[0]+cnt[1]*cnt[2]*2;
}

void dfs(int x)
{
    max_size=inf;
    dfs_size(x,-1);
    dfs_root(x,x,-1);
    ans+=get_num(root,0);
    ha[root]=1;
    for(int i=head[root];i;i=nt[i])
    {
        int y=ver[i],z=edge[i];
        if(ha[y]) continue;
        ans-=get_num(y,z);
        dfs(y);
    }
}

int main(void)
{
    scanf("%d",&n);
    int x,y,z;
    for(int i=1;i<n;i++)
    {
        scanf("%d%d%d",&x,&y,&z);
        add(x,y,z);add(y,x,z);
    }
    dfs(1);
    int t=gcd(n*n,ans);
    printf("%d/%d\n",ans/t,n*n/t);

    return 0;
}