码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 2152 聪聪可可

时间:2019-02-19 20:02:37      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:答案   lin   ++i   https   namespace   分治   tchar   its   zoj   

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 聪聪可可

标签:答案   lin   ++i   https   namespace   分治   tchar   its   zoj   

原文地址:https://www.cnblogs.com/jklover/p/10403072.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!