• BZOJ2152[国家集训队]聪聪可可——点分治


    题目描述

    聪聪和可可是兄弟俩,他们俩经常为了一些琐事打起来,例如家中只剩下最后一根冰棍而两人都想吃、两个人都想玩儿电脑(可是他们家只有一台电脑)……遇到这种问题,一般情况下石头剪刀布就好了,可是他们已经玩儿腻了这种低智商的游戏。他们的爸爸快被他们的争吵烦死了,所以他发明了一个新游戏:由爸爸在纸上画n个“点”,并用n-1条“边”把这n个“点”恰好连通(其实这就是一棵树)。并且每条“边”上都有一个数。接下来由聪聪和可可分别随即选一个点(当然他们选点时是看不到这棵树的),如果两个点之间所有边上数的和加起来恰好是3的倍数,则判聪聪赢,否则可可赢。聪聪非常爱思考问题,在每次游戏后都会仔细研究这棵树,希望知道对于这张图自己的获胜概率是多少。现请你帮忙求出这个值以验证聪聪的答案是否正确。

    输入

    输入的第1行包含1个正整数n。后面n-1行,每行3个整数x、y、w,表示x号点和y号点之间有一条边,上面的数是w。

    输出

    以即约分数形式输出这个概率(即“a/b”的形式,其中a和b必须互质。如果概率为1,输出“1/1”)。

    样例输入

    5
    1 2 1
    1 3 2
    1 4 1
    2 5 3

    样例输出

    13/25
    【样例说明】
    13组点对分别是(1,1) (2,2) (2,3) (2,5) (3,2) (3,3) (3,4) (3,5) (4,3) (4,4) (5,2) (5,3) (5,5)。

    【数据规模】
    对于100%的数据,n<=20000。
     
     
    点分治入门题,因为满足逆运算,所以只要单步容斥统计出子树中路径长%3=0,%3=1,%3=2的方案数,再减掉同一棵子树中的方案数即可。因为一对点反过来算另一种方案且节点和自己也计入答案,所以答案要x2。注意树的大小及最大子树大小初始值要赋成n。
    最后附上代码。
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    int n,k;
    int tot;
    int num;
    int ans;
    int sum;
    int root;
    int x,y,z;
    int s[4];
    int to[60000];
    int mx[30000];
    int val[60000];
    int head[30000];
    int next[60000];
    int size[30000];
    bool vis[30000];
    int gcd(int a,int b)
    {
        if(b!=0)
        {
            return gcd(b,a%b);
        }
        else
        {
            return a;
        }
    }
    void add(int x,int y,int v)
    {
        tot++;
        next[tot]=head[x];
        head[x]=tot;
        to[tot]=y;
        val[tot]=v;
        tot++;
        next[tot]=head[y];
        head[y]=tot;
        to[tot]=x;
        val[tot]=v;
    }
    void getroot(int x,int fa)
    {
        size[x]=1;
        mx[x]=0;
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=fa&&!vis[to[i]])
            {
                getroot(to[i],x);
                size[x]+=size[to[i]];
                mx[x]=max(mx[x],size[to[i]]);
            }
        }
        mx[x]=max(mx[x],num-size[x]);
        if(!root||mx[x]<mx[root])
        {
            root=x;
        }
    }
    void dfs(int x,int fa,int dis)
    {
        s[dis%3]++;
        for(int i=head[x];i;i=next[i])
        {
            if(to[i]!=fa&&!vis[to[i]])
            {
                dfs(to[i],x,dis+val[i]);
            }
        }
    }
    int calc(int x,int v)
    {
        int ans=0;
        s[0]=s[1]=s[2]=0;
        dfs(x,0,v);
        return s[1]*s[2]*2+s[0]*s[0];
    }
    void partition(int x)
    {
        vis[x]=1;
        ans+=calc(x,0);
        for(int i=head[x];i;i=next[i])
        {
            if(!vis[to[i]])
            {
                ans-=calc(to[i],val[i]);
                num=size[to[i]];
                root=0;
                getroot(to[i],0);
                partition(root);
            }
        }
    }
    int main()
    {   
        scanf("%d",&n);
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z%3);
        }
        mx[0]=num=n;
        getroot(1,0);
        partition(root);
        sum=n*n;
        int g=gcd(ans,sum);
        ans/=g;
        sum/=g;
        printf("%d/%d",ans,sum);
    }
  • 相关阅读:
    基于ZKEACMS的.Net Core多租户CMS建站系统
    使用PowerShell自动部署ASP.NetCore程序到IIS
    在Linux安装ASP.Net Core的运行时(Runtime)
    ASP .Net Core 2.0 修改默认端口
    .Net Core内存回收模式及性能测试对比
    .Net Core配置与自动更新
    Razor TagHelper实现Markdown转HTML
    用Docker自动构建纸壳CMS
    纸壳CMS 2.3,正式加入商城功能
    Linux使用私钥公钥(Public key)登录
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/9185784.html
Copyright © 2020-2023  润新知