点分治

今天学的算法,呀。其实之前打比赛时做到过类似的题目。
当时没有去补题,感觉怪难的。现在学学。

点分治主要是用于求解树上路径类的问题。
这题如果能想到点分治的话,思路其实还是挺清晰的。
但是,刚学,我板子写错了哦

#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e5+100;
const int inf=1e9;
struct edge{
    int to,cost,next;
}E[N<<1];
int head[N];
int cnt=1;
void add(int from,int to,int cost){
    E[cnt].to=to;E[cnt].cost=cost;
    E[cnt].next=head[from];
    head[from]=cnt++;
}

int root;
int maxson[N],size[N];
int sig;
bool vis[N];

void getroot(int u,int fa){
    size[u]=1;maxson[u]=0;
    for (int i=head[u];i;i=E[i].next){
        int v=E[i].to;int cost=E[i].cost;
        if (vis[v]||v==fa)continue;
        getroot(v,u);
        size[u]+=size[v];
        maxson[u]=max(maxson[u],size[v]);
    }maxson[u]=max(maxson[u],sig-size[u]);
    if(maxson[u]<maxson[root])root=u;
}
ll res[3];
void getrood(int u,int fa,ll len){
    res[len%3]++;
    for (int i=head[u];i;i=E[i].next){
        int v=E[i].to;int cost=E[i].cost;
        if (vis[v]||v==fa)continue;
        getrood(v,u,len+cost);
    }
}

ll Solve(int u,ll len){
    res[0]=res[1]=res[2]=0;
    getrood(u,0,len);
    return res[0]*res[0]+res[1]*res[2]*2;
}

ll ans=0;
void dfs(int u){
    vis[u]=1;
    ans+=Solve(u,0);
    for (int i=head[u];i;i=E[i].next){
        int v=E[i].to;int cost=E[i].cost;
        if (vis[v])continue;
        ans-=Solve(v,cost);
        root=0;sig=size[v];
        getroot(v,u);
        dfs(root);
    }
}

int n;

int main(){
    ios::sync_with_stdio(0);
    cin>>n;
    for (int i=1,u,v,w;i<n;++i){
        cin>>u>>v>>w;w%=3;
        add(u,v,w);add(v,u,w);
    }
    sig=n;root=0;
    maxson[0]=inf;
    getroot(1,0);
    dfs(root);
    ll c=__gcd(ans,(ll)n*(ll)n);
    cout<<ans/c<<"/"<<(ll)n*(ll)n/c<<endl;
}