bzoj 2152 聪聪可可

Posted jklover

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2152 聪聪可可相关的知识,希望对你有一定的参考价值。

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
",ans/g,1LL*n*n/g);
    return 0;
}

以上是关于bzoj 2152 聪聪可可的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2152: 聪聪可可 [点分治]

[bzoj 2152] 聪聪可可 树上点分治

bzoj 2152 聪聪可可(点分治模板)

bzoj 2152 聪聪可可

bzoj 2152: 聪聪可可

BZOJ 2152 聪聪可可