[国家集训队]聪聪可可

题目:洛谷P2634、BZOJ2152。

题目大意:有n个点,每个点有一个权值。现在两个人分别选两个点,如果两点的最短路在3进制下个位相等,则规定获胜。求总胜率(获胜选法/所有可能选法),两个人选的不同点调换算两种方案。

解题思路:点分治,每次找出树的重心,然后以重心为根,递归处理。

每次统计模3余0 1 2的个数,然后计算答案即可。

注意要去掉一些走非最短路径的(即重复)。

时间复杂度$O(nlog_2 n)$。

C++ Code:

#include<bits/stdc++.h>
#define _ __;i
nt m
ain(
){}
inline int max(int a,int b){return a>b?a:b;}
inline int debian(){
    int c=getchar();
    for(;!isdigit(c);c=getchar());
    int d=0;
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
    return d;
}
int __gcd(int a,int b){return b?__gcd(b,a%b):a;}
static class Main{
    private:
    int n,cnt,head[20005],rt,sz,f[20005],son[20005],ct[3],d[20005],ans;
    bool ur[20005];
    struct edge{
        int to,nxt,dis;
    }e[40005];
    void getdp(int now,int pre){
        ++ct[d[now]];
        for(int i=head[now];i;i=e[i].nxt)
        if(e[i].to!=pre&&!ur[e[i].to]){
            d[e[i].to]=(d[now]+e[i].dis)%3;
            getdp(e[i].to,now);
        }
    }
    int calc(int now,int v){
        ct[0]=ct[1]=ct[2]=0;
        d[now]=v;
        getdp(now,0);
        return ct[0]*ct[0]+((ct[1]*ct[2])<<1);
    }
    void getrt(int now,int pre){
        son[now]=1;
        f[now]=0;
        for(int i=head[now];i;i=e[i].nxt)
        if(!ur[e[i].to]&&e[i].to!=pre){
            getrt(e[i].to,now);
            son[now]+=son[e[i].to];
            f[now]=max(f[now],son[e[i].to]);
        }
        f[now]=max(f[now],sz-son[now]);
        if(f[now]<f[rt])rt=now;
    }
    void dfz(int now){
        ur[now]=true;
        ans+=calc(now,0);
        for(int i=head[now];i;i=e[i].nxt)
        if(!ur[e[i].to]){
            ans-=calc(e[i].to,e[i].dis);
            rt=0;
            sz=son[e[i].to];
            getrt(e[i].to,0);
            dfz(rt);
        }
    }
    public:
    Main():n(debian()),cnt(0),rt(0),ans(0){
        memset(head,0,sizeof head);
        for(int i=1;i<n;++i){
            int x=debian(),y=debian(),z=debian()%3;
            e[++cnt]=(edge){y,head[x],z};
            head[x]=cnt;
            e[++cnt]=(edge){x,head[y],z};
            head[y]=cnt;
        }
        sz=f[0]=n;
        memset(ur,0,sizeof ur);
        getrt(1,0);
        dfz(rt);
        int gcd=__gcd(ans,n*n);
        exit(!printf("%d/%d
",ans/gcd,n*n/gcd));
    }
}_
原文地址:https://www.cnblogs.com/Mrsrz/p/8634430.html