zoukankan      html  css  js  c++  java
  • BZOJ2152: 聪聪可可

    【传送门:BZOJ2152


    简要题意:

      给出一棵n个点的树,和每条边的边权,求出有多少个点对,它们的距离为3的倍数

      最后输出求出的点对数/总点对数的最简分数


    题解:

      点分治例题

      求值时设t[i]为路径的值%3==i的情况数,那么答案就为t[1]*t[2]*2+t[0]*t[0]


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    struct node
    {
        int x,y,d,next;
    }a[81000];int len,last[41000];
    void ins(int x,int y,int d)
    {
        len++;
        a[len].x=x;a[len].y=y;a[len].d=d;
        a[len].next=last[x];last[x]=len;
    }
    int tot[41000],root,sum,ms[41000];
    bool v[41000];
    void getroot(int x,int fa)
    {
        tot[x]=1;ms[x]=0;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fa&&v[y]==false)
            {
                getroot(y,x);
                tot[x]+=tot[y];
                ms[x]=max(ms[x],tot[y]);
            }
        }
        ms[x]=max(ms[x],sum-tot[x]);
        if(ms[root]>ms[x]) root=x;
    }
    int t[3];
    void ask(int x,int fa,int d)
    {
        t[d%3]++;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fa&&v[y]==false)
            {
                ask(y,x,(d+a[k].d)%3);
            }
        }
    }    
    int ans=0;
    int k;
    int cal(int x,int d)
    {
        t[0]=t[1]=t[2]=0;
        ask(x,0,d);
        return 2*t[1]*t[2]+t[0]*t[0];
    }
    void solve(int x)
    {
        ans+=cal(x,0);
        v[x]=true;
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(v[y]==false)
            {
                ans-=cal(y,a[k].d);
                sum=tot[y];
                ms[0]=1<<31-1;
                root=0;getroot(y,x);
                solve(root);
            }
        }
    }
    int gcd(int a,int b)
    {
        if(a==0) return b;
        else return gcd(b%a,a);
    }
    int main()
    {
        int n;
        scanf("%d",&n);
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<n;i++)
        {
            int x,y,d;
            scanf("%d%d%d",&x,&y,&d);
            ins(x,y,d);ins(y,x,d);
        }
        memset(v,false,sizeof(v));
        ans=0;
        sum=n;
        ms[0]=1<<31-1;
        root=0;getroot(1,0);
        solve(root);
        int all=n*n;
        int GCD=gcd(ans,all);
        printf("%d/%d
    ",ans/GCD,all/GCD);
        return 0;
    }

     

  • 相关阅读:
    1021. 从前有座山——java
    1004. 西西弗斯式的命运——java
    1025. 水枪灭火——java
    1020. 分解质因数——java
    1024.排序——C语言
    1024. 排序——java
    1022. Fib数列——java
    1006. 求和游戏——java
    1005. 数独——java
    SpringBoot 升级到 2.1 后,启动程序时控制台不打印 API 的解决方法及一些感想
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8961515.html
Copyright © 2011-2022 走看看