zoukankan      html  css  js  c++  java
  • 洛谷P2634 聪聪可可 (点分治)

    ###题目链接###

    题目大意:

    给你一棵树,假如树上两点间的距离是 3 的倍数 的点对有 s 对,则输出最简分数  s/n ,其中 n 表示所有整棵树的点对总数。

    分析:

    1、显然,可以采用点分治。

    2、当然考虑到数据过大,点分治中求距离时,可以不需要把真实距离依次存入 dis[] 数组中。可以将每个距离值 %3  ,这样如果有两个距离 x    y ,若使 x + y 为 3 的倍数,只需要满足两点:

    • x%3==0  &&  y%3==0 
    • x%3==1  &&  y%3==2

    上述 x   y 可交换。故只需要用 vis[0] 、vis[1] 、 vis[2] 来标记距离,然后求和即可。

    代码如下:

    #include<iostream>
    #include<algorithm>
    #include<string.h>
    #define maxn 20008
    #define inf 0x3f3f3f3f
    using namespace std;
    bool vis[maxn];
    int n,cnt,root,size,ans;
    int head[maxn],sz[maxn],f[maxn],flag[4];
    struct Edge{
        int to;
        int val;
        int next;
    }edge[maxn<<1];
    inline void add(int u,int v,int w){
        edge[++cnt].to=v;
        edge[cnt].val=w;
        edge[cnt].next=head[u];
        head[u]=cnt;
        return;
    }
    int gcd(int a,int b){
        if(!b) return a;
        return gcd(b,a%b);
    }
    void  getdis(int u,int pre,int d){
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(v==pre||vis[v]) continue;
            flag[(d+edge[i].val)%3]++;
            getdis(v,u,d+edge[i].val);
        }
        return;
    }
    void calc(int u,int d,int s){
        flag[0]=flag[1]=flag[2]=0;
        flag[d%3]++;
        getdis(u,-1,d);
        ans+=s*flag[0]*(flag[0]-1);
        ans+=s*flag[1]*flag[2]*2;
        return;
    }
    void  getroot(int u,int pre){
        sz[u]=1,f[u]=0;
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(v==pre||vis[v]) continue;
            getroot(v,u);
            sz[u]+=sz[v];
            f[u]=max(f[u],sz[v]);
        }
        f[u]=max(f[u],size-sz[u]);
        if(f[u]<f[root]) root=u;
        return;
    }
    void divide(int u){
        vis[u]=true;
        calc(u,0,1);
        int sum=size;
        for(int i=head[u];i;i=edge[i].next){
            int v=edge[i].to;
            if(vis[v]) continue;
            calc(v,edge[i].val,-1);
            size=sz[v]>sz[u]?sum-sz[u]:sz[v];
            root=0;
            getroot(v,-1);
            divide(root);
        }
        return;
    }
    int main()
    {
        scanf("%d",&n);
        int x,y,w;
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&x,&y,&w);
            add(x,y,w),add(y,x,w);
        }
        root=0;
        f[root]=inf;
        size=n;
        getroot(1,-1);
        divide(root);
        ans+=n;
        int t=n*n;
        int g=gcd(ans,t);
        ans/=g,t/=g;
        printf("%d/%d
    ",ans,t);
    }
  • 相关阅读:
    per-CPU变量
    oom killer
    System.map文件的作用
    Linux电源管理(9)_wakelocks【转】
    Linux内核的冷热缓存
    浅谈TCP IP协议栈(四)IP协议解析
    浅谈TCP IP协议栈(三)路由器简介
    CFS调度器(1)-基本原理
    浅谈TCP IP协议栈(二)IP地址
    (利用DOM)在新打开的页面点击关闭当前浏览器窗口
  • 原文地址:https://www.cnblogs.com/Absofuckinglutely/p/11945974.html
Copyright © 2011-2022 走看看