bzoj2152 (点分治)

Posted kls123

tags:

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

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2152

思路:

要想两点之间距离为3的倍数,那么用t0表示该点距离重心的距离对3取模为0,依此得t1,t2,那么两点之间距离为3的倍数只有三种可能:t1-t2,t2-t1,t0-t0,将所有和重心的具体全部统计好,最后t1*t2*2+t0*t0就是

为3的倍数的点对数量

实现代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x7fffffff
const int M = 1e5+10;
int siz[M],f[M],head[M],vis[M],ans,cnt,t[M],sum,root,d[M];
struct node{
    int to,next,w;
}e[M<<1];

void init(){
    ans = 0;
    cnt = 0;
    memset(vis,0,sizeof(vis));
    memset(head,0,sizeof(head));
}

void add(int u,int v,int w){
    e[++cnt].to = v; e[cnt].w = w; e[cnt].next = head[u]; head[u] = cnt;
}

void get_root(int u,int fa){
    siz[u] = 1; f[u] = 0;
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != fa&&!vis[v]){
            get_root(v,u);
            siz[u] += siz[v];
            f[u] = max(f[u],siz[v]);
        }
    }
    f[u] = max(f[u],sum - siz[u]);
    if(f[u] < f[root]) root = u;
    return ;
}

void get_dis(int u,int fa){
    t[d[u]]++;
    for(int i = head[u];i;i = e[i].next){
        int v = e[i].to;
        if(v != fa&& !vis[v]){
            d[v] = (d[u] + e[i].w)%3;
            get_dis(v,u);
        }
    }
    return ;
}

int cal(int u,int c){
    t[0] = t[1] = t[2] = 0;
    d[u] = c;
    get_dis(u,0);
    return t[1]*t[2]*2+t[0]*t[0];
}

void solve(int v){
    ans += cal(v,0); vis[v] = 1;
    for(int i = head[v];i;i = e[i].next){
        int v = e[i].to;
        if(!vis[v]){
            ans -= cal(v,e[i].w);
            sum = siz[v];
            root = 0;
            get_root(v,0);
            solve(root);
        }
    }
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    int m,u,v,w,n;
    cin>>n;
    init();
    for(int i = 1;i <= n-1;i ++){
        cin>>u>>v>>w;
        w%=3;
        add(u,v,w);
        add(v,u,w);
    }
    f[0] = inf;
    sum = n;
    root = 0;
    get_root(1,0);
    solve(root);
    int x = __gcd(ans,n*n);
    cout<<ans/x<<"/"<<n*n/x<<endl;
    return 0;
}

 

以上是关于bzoj2152 (点分治)的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 2152 聪聪可可 | 树的点分治

BZOJ2152 点分治入门

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

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

BZOJ 2152 「国家集训队」聪聪可可(点分治)BZOJ计划

BZOJ 2152 「国家集训队」聪聪可可(点分治)BZOJ计划