zoukankan      html  css  js  c++  java
  • Codeforces Round #588 (Div. 2) E. Kamil and Making a Stream(dfs)

    题意:

    给一棵 \(n\) 个节点的树,定义 \(f(u,v)\),其中 \(u\)\(v\) 的祖先,\(f(u,v)\) 等于 \(u\) \(\rightarrow\) \(v\) 路径上所有点权值的 \(gcd\)。现求一棵树上所有的 \(f(u,v)\) 之和。

    分析:

    简单的 \(dfs\),难点可能在于不好估计复杂度。一棵树上所有的 \(f(u,v)\) \((u!=v)\) 权值数不会超过 \(log_2(1e12)\) 种,暴力即可。
    我们用一个 \(map\) 记录每个点的祖先到其的 \(gcd\) 和到这个点的 \(gcd\) 出现的次数,那么就可以计算贡献了。因为 \(f(u,v)\) 权值数不会超过 \(log_2(1e12)\) 种,所以对每个节点暴力向其孩子求贡献的总复杂度是 \(O(nlog_2(1e12))\)

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    #define pb push_back
    
    const int N = 1e5 + 5;
    const LL mod = 1e9 + 7;
    
    int n, u, v;
    LL ans, w[N];
    vector<int> g[N];
    unordered_map<LL, int> maps[N];
    
    void add(int u, LL w, int p) {
    	ans = (ans + 1LL * p * w % mod) % mod;
    	maps[u][w] += p;
    }
    
    void dfs(int u, int f) {
    	add(u, w[u], 1);
    	for (auto it : g[u]) {
    		if (it == f) continue;
    		for (auto it1 : maps[u]) add(it, __gcd(w[it], it1.first), it1.second);
    		dfs(it, u);
    	}
    }
    
    int main() { 
    	scanf("%d", &n);
    	for (int i = 1; i <= n; i++) scanf("%lld", w + i);
    	for (int i = 1; i <= n - 1; i++) {
    		scanf("%d %d", &u, &v);
    		g[u].pb(v), g[v].pb(u);
    	}
    	dfs(1, -1);
    	printf("%lld\n", ans);
    	return 0;
    }
    
  • 相关阅读:
    快速幂
    Oracle悲观锁和乐观锁
    UTL_RAW的问题?
    Linux操作系统下关于Top命令的参数详解
    存储过程与函数
    网站前端优化一些小经验
    Java获取各种常用时间方法2
    Pro CSS Techniques 读书笔记(六)
    Java获取各种常用时间方法
    Oracle专用服务器与共享服务器的区别
  • 原文地址:https://www.cnblogs.com/ChaseNo1/p/11588231.html
Copyright © 2011-2022 走看看