1. 程式人生 > >bzoj 2152 聰聰可可

bzoj 2152 聰聰可可

復雜度 using ont 計算 時間 每次 return ble ots

bzoj 2152 聰聰可可

  • 類似於點分治板子那道題,但是本題的 \(n\) 更大,而在模 \(3\) 意義下計算邊權和很小,在計算子樹路徑時,可以開一個桶 \(tot[3]\) 記錄每個權值的路徑條數.
  • 合並時就不用枚舉路徑了,對答案貢獻顯然直接就是 \(2*tot[1]*tot[2]+tot[0]^2\).
  • 這樣做每次合並的時間復雜度為常數級,總時間復雜度為 \(O(nlogn)\).
  • 這個方法(可能?)只對邊權和很小的時候適用,每次合並是邊權大小的時間復雜度.邊權較大時,若用 \(map\) 代替桶,也會多一個 \(log\) ,和暴力枚舉是同級的.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define mp make_pair
#define pii pair<int,int>
inline int read()
{
    int x=0;
    bool pos=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar())
        if(ch=='-')
            pos=0;
    for(;isdigit(ch);ch=getchar())
        x=x*10+ch-'0';
    return pos?x:-x;
}
#define inf 1e9
const int MAXN=2e4+10;
int n;
int cnt=0,head[MAXN],to[MAXN<<1],nx[MAXN<<1],val[MAXN<<1];
ll ans,tot[3];
int stk[MAXN],tp;
int vis[MAXN];
int totsiz,siz[MAXN],sonsiz[MAXN],mi,rt;
inline void addedge(int u,int v,int w)
{
    ++cnt;
    nx[cnt]=head[u];
    to[cnt]=v;
    val[cnt]=w;
    head[u]=cnt;
}
void ins(int u,int v,int w)
{
    addedge(u,v,w);
    addedge(v,u,w);
}
void getroot(int u,int fa)
{
    siz[u]=1;
    sonsiz[u]=0;
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            if(vis[v] || v==fa)
                continue;
            getroot(v,u);
            siz[u]+=siz[v];
            if(siz[v]>sonsiz[u])
                sonsiz[u]=siz[v];
        }
    sonsiz[u]=max(sonsiz[u],totsiz-siz[u]);
    if(sonsiz[u]<mi)
        mi=sonsiz[u],rt=u;
}
void getdis(int u,int fa,int len)
{
    ++tot[len%3];
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            if(vis[v] || v==fa)
                continue;
            getdis(v,u,(len+val[i])%3);
        }
}
void solve(int rt,int len,int val)
{
    tot[0]=tot[1]=tot[2]=0;
    getdis(rt,0,len);
    ans+=val*(2*tot[1]*tot[2]+tot[0]*tot[0]);
}
void Divide(int u)
{
    vis[u]=1;
    solve(u,0,1);
    for(int i=head[u];i;i=nx[i])
        {
            int v=to[i];
            if(vis[v])
                continue;
            solve(v,val[i],-1);
            mi=inf;
            totsiz=siz[v];
            getroot(v,0);
            Divide(rt);
        }
}
ll gcd(ll a,ll b)
{
    return b?gcd(b,a%b):a;
}
int main()
{
    n=read();
    for(int i=1;i<n;++i)
        {
            int u=read(),v=read(),w=read();
            ins(u,v,w%3);
        }
    mi=inf;
    totsiz=n;
    getroot(1,0);
    Divide(1);
    ll g=gcd(ans,1LL*n*n);
    printf("%lld/%lld\n",ans/g,1LL*n*n/g);
    return 0;
}

bzoj 2152 聰聰可可