题目:https://vjudge.net/contest/307753#problem/G

题意: 一棵树让你求总的路径条数和 %3的路径条数

思路:点分治水题

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream> 
#include<vector>
#include<queue>
#define maxn 100005
#define mod 0x3f3f3f3f
using namespace std;
typedef long long ll;
ll da;
vector<pair<ll,ll> > mp[maxn],xx[maxn];//存下图 
ll e[maxn];
bool vis[maxn];//标记曾经使用过的重心 
ll maxsize[maxn],dis[maxn],d[maxn],flag[maxn];//maxsize 当前节点的最大子树 
ll siz[maxn],xd[maxn];// dis 到重心的距离  d 出现过的距离 
ll n,m,k,rt,sum,qe,qe2,ans1,ans2;  // siz 当前节点的子树个数  e 出现的距离  rt代表当前重心 
void find(ll x,ll f){//找出重心 
    siz[x]=1;
    maxsize[x]=0;
    for(int i=0;i<mp[x].size();i++){
        pair<ll,ll> q=mp[x][i];
        if(q.first==f||vis[q.first]) continue;//vis数组标记曾经使用过的重心 
        find(q.first,x);
        siz[x]+=siz[q.first];
        maxsize[x]=max(maxsize[x],siz[q.first]); 
    } 
    maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数 
    if(maxsize[x]<maxsize[rt]){
        rt=x;
    } 
}
void query(ll z,ll sm){
    if(z>ans1){
        ans1=z;
        ans2=sm;
    }
    else if(z==ans1){
        ans2+=sm;
    }
}
void get_dis(ll x,ll f,ll len){
    
    if(len%3==0) ans1++;
    ans2++;
    ans1+=flag[(3-len%3+3)%3];
    ans2+=flag[0]+flag[1]+flag[2];
    e[len%3]++;
    for(int i=0;i<mp[x].size();i++){
        pair<ll,ll> q=mp[x][i];
        if(q.first==f||vis[q.first]) continue;
        //dis[q.first]=(dis[x]+len)%3;
        get_dis(q.first,x,(len+q.second)%3);
    }    
}
void divide(ll x){
    vis[x]=1;
    //printf("rt=%lld ans1=%lld ans2=%lld\n",x,ans1,ans2);
    for(int i=0;i<mp[x].size();i++){
        pair<ll,ll> q=mp[x][i];
        if(vis[q.first]) continue;
        //dis[x]=q.second;
        get_dis(q.first,x,q.second%3);
        for(int j=0;j<3;j++){
            flag[j]+=e[j];
            e[j]=0;
        }
    }
    for(int i=0;i<3;i++){
        flag[i]=0;
    }
    for(int i=0;i<mp[x].size();i++){
        pair<ll,ll> q=mp[x][i];
        if(vis[q.first]) continue;
        //if(da>0) break;
        sum=siz[q.first];
        rt=0;
        maxsize[rt]=mod;
        find(q.first,x);
        divide(rt);
    }
//    vis[x]=0;
}
void init(){
    ans1=0;ans2=0;
    for(int i=0;i<=n;i++) mp[i].clear();
    for(int i=0;i<=n;i++) vis[i]=0;
    for(int i=0;i<3;i++) flag[i]=0;
} 
int main(){
    ll t;
    while(scanf("%lld",&n)!=EOF){
        ll a,b,c;
        init();
        for(int i=1;i<=n-1;i++){
            scanf("%lld%lld%lld",&a,&b,&c);
            mp[a].push_back(make_pair(b,c));
            mp[b].push_back(make_pair(a,c)); 
        }    
        sum=n;//当前节点数 
        rt=0;
        maxsize[0]=mod;//置初值 
        find(1,0);
        divide(rt);
        ans1*=2;
        ans2*=2;
        ans1+=n;
        ans2+=n;
        ll w=__gcd(ans1,ans2);
        //printf("%lld/%lld\n",ans1,ans2);
        printf("%lld/%lld\n",ans1/w,ans2/w);
    
    }
}