7. 子树边权平方和

2024-03-28 22:38
文章标签 子树 平方和 边权

本文主要是介绍7. 子树边权平方和,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这是别人问我的题,所以没有题目链接,名字也是我随便起的。

有一棵包含 n n n 个节点的树,节点编号从 1 1 1 n n n,以 1 1 1 为根,每条边都有一个权值。给你 m m m 次询问,每次询问一个子树,在子树中对每种边权的值 c c c 统计出现次数 c n t c cnt_{c} cntc,求 ∑ ( c ⋅ c n t c ) 2 \sum(c\cdot cnt_c)^2 (ccntc)2

n , m n,m n,m 以及边权范围均为 1 × 1 0 5 1\times 10^5 1×105

容易发现可以将边权下放到点,并且这个平方和很好维护,增删一个权值都可以 O ( 1 ) O(1) O(1) 完成。那么可以用 dsu on tree 来做,先预处理出所有节点的最大子树,然后 dfs 的时候先算所有小子树再算大子树,最后暴力合并小子树即可。时间复杂度 O ( n log ⁡ n ) O(n\log n) O(nlogn)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using pii = pair<int, int>;
const int maxn = 1e5 + 5;
ll weight[maxn], ans[maxn];
vector<int> g[maxn], id[maxn];
int sz[maxn], son[maxn];
void dfs0(int u) {sz[u] = 1;for (auto v : g[u]) {dfs0(v);sz[u] += sz[v];if (sz[v] > sz[son[u]])son[u] = v;}
}
int cnt[maxn], vis[maxn];
ll sum;
void clear(int u) {sum -= (weight[u] * cnt[weight[u]]) * (weight[u] * cnt[weight[u]]);cnt[weight[u]]--;sum += (weight[u] * cnt[weight[u]]) * (weight[u] * cnt[weight[u]]);for (auto v : g[u])clear(v);
}
void dfs(int u, int op) {for (auto v : g[u]) {if (v == son[u])continue;dfs(v, 0);}if (son[u]) {dfs(son[u], 1);}for (auto v : g[u]) {if (v == son[u])continue;dfs(v, 1);}if (!vis[u]) {for (auto x : id[u]) {ans[x] = sum;}vis[u] = 1;}sum -= (weight[u] * cnt[weight[u]]) * (weight[u] * cnt[weight[u]]);cnt[weight[u]]++;sum += (weight[u] * cnt[weight[u]]) * (weight[u] * cnt[weight[u]]);if (!op) {clear(u);}
}
void solve() {int n, m, c, q;cin >> n >> m >> c;for (int i = 1, u, v, w; i < n; ++i) {cin >> u >> v >> w;g[u].push_back(v);weight[v] = w;}for (int i = 1, x; i <= m; ++i) {cin >> x;id[x].push_back(i);}dfs0(1);dfs(1, 1);for (int i = 1; i <= m; ++i) {cout << ans[i] << '\n';}
}
int main() {ios::sync_with_stdio(false);cin.tie(nullptr);solve();return 0;
}

这篇关于7. 子树边权平方和的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/856886

相关文章

【HDU】5574 Colorful Tree【子树染色,询问子树颜色数——线段树+bit+lca+set】

题目链接:【HDU】5574 Colorful Tree 题目大意:对一个子树染色,询问一个子树的颜色数。 题目分析: set set维护每种颜色所在的 dfs dfs序区间,修改均摊 nlogn nlogn。 #include <bits/stdc++.h>using namespace std ;typedef long long LL ;typedef pair < int , i

Golang-指定文本,求奇数行正数平方和

在stack看到HENNGE公司的招聘信息,于是去参加了一次线上笔试。对方法发了三道题,此为第一道题——使用Golang处理文本。 下为要求: 仔细思考后,发现一个规律: 第1行指定总行数;偶数行n指定下一行奇数行n+1行的个数;全部数据喂完后出结果,意味着最后是扔进数组,放到最后遍历。 提示: 要求不能使用for;只能使用基本库。 因为Golang的循环语句出来了for,只剩下g

git如何设置嵌套仓库(设置子树或子模块),并解决直接将一个仓库拖拽到另一个仓库中导致的问题

git 将一个仓库拷贝到另一个仓库的文件夹下。默认git并不会处理,上传上去之后,只会创建一个文件夹,但是这个文件夹点不开。 在 git add . 的时候,会报出警告: 警告:正在添加嵌入式 git 仓库:client提示: You've added another git repository inside your current repository.提示: Clones of

算法---------寻找重复的子树(Java版本)

题目描述: 给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。两棵树重复是指它们具有相同的结构以及相同的结点值。示例 1:1/ \2 3/ / \4 2 4/4下面是两个重复的子树:2/4和4因此,你需要以列表的形式返回上述重复子树的根结点。 解决方法: /*** Definition for a binary tree n

2166. 子树的大小及深度

代码 #include<bits/stdc++.h>using namespace std;vector<int> a[110];int d[110],s[110];int dfs(int x,int y){int i;s[x]=1;d[x]=d[y]+1;for(i=0;i<a[x].size();i++)if(a[x][i]!=y)s[x]=s[x]+dfs(a[x][i

数据结构-非线性结构-树形结构:有序树 ->二叉树 -> 平衡二叉树(任何节点的左右子树的高度差不大于1)-> 完全二叉树(除最底层外的其他层都被填满,且最底层左到右填入) -> 堆(优先队列)

完全二叉树:即除了最底层,其他层的节点都被元素填满,且最底层左到右填入。 完全二叉树属于平衡二叉树。 堆是一种完全二叉树,且满足以下条件: 最大堆:每个节点都比其子树所有节点大的完全二叉树;最小堆:每个节点都比其子树所有节点小的完全二叉树; 我们对堆中的结点按层进行编号,可以将堆逻辑结构映射到数组中 大顶堆:arr[i] >= arr[2i+1] && arr[i] >= arr[2i

leetcode刷题(98)——652. 寻找重复的子树

给定一棵二叉树,返回所有重复的子树。对于同一类的重复子树,你只需要返回其中任意一棵的根结点即可。 两棵树重复是指它们具有相同的结构以及相同的结点值。 示例 1: 1/ \2 3/ / \4 2 4/4 下面是两个重复的子树: 2/4 和 4 因此,你需要以列表的形式返回上述重复子树的根结点。 /*** Definition for a binar

[CSU - 1811 (湖南省赛16)] Tree Intersection (dfs序维护子树+离线询问+树状数组)

CSU - 1811 (湖南省赛16) 给定一棵树,每个节点都有一个颜色 问割掉任意一条边,生成的两个子树中颜色集合的交集大小 这个是 dfs序处理子树 + 离线询问 + bit维护 的解法 首先问题转化为求解一个子树中有多少种颜色以及独有颜色的数量 用总的颜色数量减去独有颜色数量即为这棵子树的答案 先做一遍 dfs,再按 dfs序重新组建颜色序列 这样对子树的询问,就变成

寻一棵树的子树C++(Leetcode#572.另一个树的子树)题解

官方题解有很多高大上的方法,我这就将一个最容易想到、最直接的方法吧,比较详细(基本上没有压缩代码),有不懂的可以在评论区问我~~~若有不足欢迎大佬斧正(>人<;) 首先让我们来看看这个二叉树的题目(如下图)   看完题目,明确了一棵树的子树是到叶子节点结束的,这里抛出我开始做题的想法 如何找到子树的起始点?找到起始节点后,只能说明起始节点相同,万一树 s 里的子树结构里面有很多与树 t

POJ-3522 Slim Span 最小生成树最小边权差

题目大意:n个点m条边 用n-1条边连接n个点并边权差最小 思路:枚举最小边 + Kruskal #include<stdio.h>#include<iostream>#include<string>#include<string.h>#include<math.h>#include<algorithm>#include<vector>#include<queue>u