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

    题意

    Here

    思考

    最近学习一下点分治

    本题点分治裸题,也可以用树形 (dp) 做,在此记录一下点分治的做法:

    首先题目要求求出边权和为 (3) 的倍数的路径个数和,那么我们可以将路径和对 (3) 取模,树上路径就只分为了三种: (0, 1, 2),用一个桶记录个数,那么每次点分治计算的答案就是 (sum[0] * sum[0] + sum[1] * sum[2]),(两条路径为(0)的链和一条路径为(1)的链(+)一条路径为(2)的链,由于后者的起点和中点的位置可以互换,所以就是乘法原理~)

    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 20020;
    struct node{
        int nxt, to, dis;
    }edge[N << 1];
    int head[N], num;
    void build(int from, int to, int dis){
        edge[++num].nxt = head[from];
        edge[num].to = to;
        edge[num].dis = dis;
        head[from] = num;
    }
    int dist[N], sz[N], vis[N], f[N], sum, root, ans[5], ANS;
    void getroot(int u, int fa){
        sz[u] = 1; f[u] = 0;
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == fa || vis[v]) continue;
            getroot(v, u);
            sz[u] += sz[v];
            f[u] = max(f[u], sz[v]);
        }
        f[u] = max(f[u], sum - sz[u]);
        if(f[u] < f[root]) root = u;
    }
    void getdep(int u, int fa){
        dist[u] %= 3;
        ans[dist[u]] ++;
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == fa || vis[v]) continue;
            dist[v] = dist[u] + edge[i].dis;
            getdep(v, u);
        }
    }
    int calc(int u, int nowd){
        dist[u] = nowd;
        ans[0] = ans[1] = ans[2] = 0;
        getdep(u, 0);
        return ans[0] * ans[0] + ans[1] * ans[2] * 2;
    }
    void solve(int u, int fa){
        ANS += calc(u, 0); vis[u] = 1;
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == fa || vis[v]) continue;
            ANS -= calc(v, edge[i].dis);
            root = 0;
            sum = sz[v];
            getroot(v, u);
            solve(root, 0);
        }
    }
    int n;
    int gcd(int x, int y){
        if(y == 0) return x;
        return gcd(y, x % y);
    }
    int main(){
        cin >> n;
        for(int i=1; i<=n-1; i++){
            int u, v, d;
            cin >> u >> v >> d;
            build(u, v, d); build(v, u, d);
        }
        sum = n; f[0] = 0x3f3f3f3f; root = 0;
        getroot(1, 0);
        solve(root, 0);
        int GCD = gcd(ANS, n * n);
        cout << ANS / GCD << "/" << n * n / GCD;
        return 0;
    }
    
    

    总结

    点分治多注意一下细节就好了,记得考虑两个点在一个子树内的情况要减掉

  • 相关阅读:
    sql对日期操作
    computeroperationcommand
    Convert函数对日期的应用
    编写快速、高效的JavaScript代码
    vim常用操作技巧与配置
    PureFTPd安装配置
    关于PHP代码加密和文本加密
    父页面调用iframe里的js函数相关例程,Iframe之间通讯研究
    常用JavaScript语法100讲
    计算机端口
  • 原文地址:https://www.cnblogs.com/alecli/p/10010143.html
Copyright © 2011-2022 走看看