聰聰可可【點分治】

模板題

題目鏈接:https://www.lydsy.com/JudgeOnline/problem.php?id=2152

求長度爲3的倍數的路徑條數

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/hash_policy.hpp>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define pb push_back
#define ll long long
using namespace std;
using namespace __gnu_pbds;
const int N = 5e4+1000;
int n,k;

struct node {
    int v,w,nxt;
}edge[2*N];
int tot,head[N];
void ae(int u,int v,int w) {
    edge[++tot] = node{v,w,head[u]};
    head[u] = tot;
}
void init(int n) {
    tot = 0;
    rep(i, 1, n) head[i] = -1;
}

int siz[N],Root,wt[N],Tsiz,Tnum[4],num[4];
bool vis[N];
ll ans;
void GetRoot(int u,int f) {
    siz[u] = 1;
    wt[u] = 0;
    for(int i = head[u]; ~i ; i = edge[i].nxt) {
        int v = edge[i].v;
        if(v==f||vis[v]) continue;
        GetRoot(v,u);
        siz[u] += siz[v];
        wt[u] = max(wt[u],siz[v]);
    }
    wt[u] = max(wt[u],Tsiz-siz[u]);
    if(wt[Root]>wt[u]) Root = u;
}
void dfs(int u,int f,int dis) {
    num[dis]++;
    for(int i = head[u]; ~i ; i = edge[i].nxt) {
        int v = edge[i].v;
        int w = edge[i].w;
        if(v==f||vis[v]) continue;
        dfs(v,u,(dis+w)%3);
    }
}
void calc(int u) {
    rep(i, 0 ,2) Tnum[i] = 0;
    Tnum[0] = 1;         //注意,這裏並沒有考慮u->u這條路徑
    for(int i = head[u]; ~i ; i = edge[i].nxt) {
        int v = edge[i].v;
        int w = edge[i].w;
        if(vis[v]) continue;
        rep(i, 0, 2) num[i] = 0;
        dfs(v,u,w%3);
        rep(i, 0, 2)
            ans += 1ll*num[i]*Tnum[(3-i)%3];
        rep(i, 0, 2) Tnum[i] += num[i];
    }
}
void divide(int u) {
    calc(u);
    vis[u] = 1;         //刪掉該點
    for(int i = head[u]; ~i ; i = edge[i].nxt) {
        int v = edge[i].v;
        if(vis[v]) continue;
        Root = 0,Tsiz = siz[v];
        GetRoot(v,0);
        divide(Root);
    }
}
ll gcd(ll x, ll y) {
    return y==0?x:gcd(y,x%y);
}
int main() {
   // freopen("a.txt","r",stdin);
    //ios::sync_with_stdio(0);
    scanf("%d",&n);
    init(n);
    rep(i, 1, n-1) {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        ae(u,v,w);
        ae(v,u,w);
    }

    rep(i, 1, n) vis[i] = 0;
    wt[0] = 1e9,Tsiz = n,GetRoot(1,0),ans = 0;
    divide(Root);
    ll up = ans*2+n;
    ll down = n*n;
    ll t = gcd(up,down);
    up /= t; down /= t;
    printf("%lld/%lld",up, down);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章