• 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;
    }
  • 相关阅读:
    12-五子棋游戏:享元模式
    11-制作糖醋排骨:外观模式
    10-蒸馒头:装饰者模式
    09-公司层级结构:组合模式
    08-开关与电灯:桥接模式
    07-电源转换:适配器模式
    将博客搬至CSDN
    iview和element中日期选择器快捷选项的定制控件
    详解AJAX工作原理以及实例讲解(通俗易懂)
    最全肌肉锻炼动图
  • 原文地址:https://www.cnblogs.com/kls123/p/9323048.html
Copyright © 2020-2023  润新知