문제 P2634에 솔루션 [[대표팀] 콩 콩 코코아]

주제 링크

솔루션 [대표팀] 콩 콩 코코아

주제 효과 : 가중 나무, 두 지점이 무작위로 선택된 나무 감안할 때 두 지점 사이의 경로를 묻는 오래 할 수 있습니다 \ (3 \) 확률 나누어

점선 규칙


분석 : 확률을 계산하려면, 그때 우리는 경로의 수는 긴 될 수 있습니다 찾을 수 있습니다 \ (3 \ 것은) 나눌의 다음 총 \ (N ^ 2 \) 에 비해 경로 다른 \ (GCD의 \) 에 대한 포인트

분자에 대해서는, 모든 나무 경로를 계산해야한다, 그래서 우리는이 개 교환 순서는 우리가 마지막으로 곱한 분자 앞에 점을 뽑아서, 그리고 고려하지, 분할의 점을 고려 정복 \ (2 \) 플러스 (n \) \ 입니다 수 (동일한 교환이 여전히 2 점 방식 간주되기 때문에)

점선 규칙에 대해, 각각의 경로에 대한 우리의 통계 하위 트리에 따라 우리가 전에 얼마나 많은 경로에서 볼 필요가 있으며 길이 결합 될 수있다 \ (3 \) 로 나눌 수를

#include <cstdio>
#include <cctype>
#include <vector>
using namespace std;
const int maxn = 2e4 + 100;
inline int read(){
    int x = 0;char c = getchar();
    while(!isdigit(c))c = getchar();
    while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    return x;
}
inline int gcd(int a,int b){return !b ? a : gcd(b,a % b);}
struct Edge{int to,dist;};
vector<Edge> G[maxn];
vector<int> rem;
inline void addedge(int from,int to,int dist){G[from].push_back(Edge{to,dist});}
int maxsiz[maxn],siz[maxn],vis[maxn],dis[maxn],judge[3],tmp[3],n,rt,sum,ans1,ans2;
inline void getroot(int u,int faz = -1){
    siz[u] = 1;maxsiz[u] = 0;
    for(auto e : G[u]){
        int v = e.to;
        if(vis[v] || v == faz)continue;
        getroot(v,u);
        siz[u] += siz[v];
        maxsiz[u] = max(maxsiz[u],siz[v]);
    }
    maxsiz[u] = max(maxsiz[u],sum - siz[u]);
    if(maxsiz[u] < maxsiz[rt])rt = u;
}
inline void getdis(int u,int faz = -1){
    rem.push_back(dis[u]);
    for(auto e : G[u]){
        int v = e.to;
        if(vis[v] || v == faz)continue;
        dis[v] = (dis[u] + e.dist) % 3;
        getdis(v,u);
    }
}
inline void calc(int u){
    for(auto e : G[u]){
        int v = e.to;
        if(vis[v])continue;
        dis[v] = e.dist % 3;
        rem.clear();
        getdis(v,u);
        for(auto x : rem)
            ans1 += judge[(3 - x) % 3];
        for(auto x : rem)
            judge[x]++;
    }
    judge[0] = judge[1] = judge[2] = 0;
}
inline void solve(int u){
    vis[u] = judge[0] = 1;calc(u);
    for(auto e : G[u]){
        int v = e.to;
        if(vis[v])continue;
        sum = siz[v];maxsiz[rt = 0] = 0x7fffffff;
        getroot(v),getroot(rt),solve(rt);
    }
}
int main(){
    n = read();
    for(int u,v,w,i = 1;i < n;i++)
        u = read(),v = read(),w = read(),addedge(u,v,w),addedge(v,u,w);
    sum = n,maxsiz[rt = 0] = 0x7fffffff;
    getroot(1),solve(rt);
    ans1 = ans1 * 2 + n;
    ans2 = n * n;
    int g = gcd(ans1,ans2);
    printf("%d/%d\n",ans1 / g,ans2 / g);
    return 0;
}

추천

출처www.cnblogs.com/colazcy/p/11797027.html