zoukankan      html  css  js  c++  java
  • P2634 [国家集训队]聪聪可可

      好久好久都没有发博客了!

      不是因为我懒,就是集训的时候腾不出时间来写,真是不好意思!

      集训期间没有发博客的类型题,很快就都会补上!

      先发一篇练练手!

      点分治板子题qwq

      我一开始写的是每一次统计calc时 n暴力枚举,但是后来看题解,发现并不需要,因为一个数%3后就只有三种情况,我们可以直接根据这三种情况的个数来累加答案。  

      并且这道题和往常的点分治不一样,a到b的路径和b到a的路径并不重复,并且两个人同时选择一个点也是有可能的,并且要最简(我一开始都没看于是WA了……)

      嗯嗯上代码:

    #include<cstdio>
    #include<iostream>
    #include<queue>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    #define maxn 220010
    int head[maxn],nxt[maxn],to[maxn],w[maxn],dis[maxn],f[maxn],sz[maxn],num[3];
    bool vis[maxn];
    int cnt,n,tot,root,sum,ans;
    void add(int a,int b,int c)
    {
        to[++cnt]=b;
        nxt[cnt]=head[a];
        head[a]=cnt;
        w[cnt]=c;
    }
    void find_root(int u,int fa)
    {
        sz[u]=1;
        f[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(v==fa||vis[v]) continue;
            find_root(v,u);
            sz[u]+=sz[v];
            f[u]=max(f[u],sz[v]);
        }
        f[u]=max(f[u],sum-sz[u]);
        if(f[root]>f[u]) root=u;
    }
    void dfs(int u,int fa,int nowdis)
    {
        dis[++tot]=nowdis%3;
        num[dis[tot]]++;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(vis[v]||v==fa) continue;
            dfs(v,u,nowdis+w[i]);
        }    
    }
    int calc(int u,int nowdis)
    {
        tot=0;
        num[0]=num[1]=num[2]=0;
        dfs(u,0,nowdis%3);
        return num[0]*num[0]+num[1]*num[2]*2;
    }
    void devide(int u)
    {
        vis[u]=1;
        ans+=calc(u,0);
        for(int i=head[u];i;i=nxt[i])
        {
            int v=to[i];
            if(vis[v]) continue;
            ans-=calc(v,w[i]);
            root=0,f[0]=n,sum=sz[v];
            find_root(v,0);
            devide(root);
        }
    }
    int gcd(int a,int b)
    {
        if(b==0) return a;
        return gcd(b,a%b);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n-1;i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            add(x,y,z);
            add(y,x,z);
        }
        f[0]=sum=n;
        find_root(1,0);
        devide(root);
        int Min=gcd(ans,n*n);
        printf("%d/%d",ans/Min,n*n/Min);
        return 0;
    }

      

  • 相关阅读:
    python初体验-函数(1)
    python初体验-数值类型
    python初体验-常见错误类型
    动态规划专题——passage_1
    七夕——ORMAX(线段树)
    七夕——永远在一起(一维dp)
    动态规划4.4——背包问题
    动态规划4.3——最长公共子串问题
    动态规划4.2——子序列问题
    动态规划4.1——基础动态规划问题
  • 原文地址:https://www.cnblogs.com/popo-black-cat/p/10411747.html
Copyright © 2011-2022 走看看