小 Q 与树

给定一棵带权的树,每条边的距离都为111,要我们求∑u=1n∑v=1nmin(au,av)dis(u,v)\sum\limits_{u = 1} ^{n} \sum\limits_{v = 1} ^{n}min(a_u, a_v)dis(u, v)u=1∑n​v=1∑n​min(au​,av​)dis(u,v),
min(au,av)dis(u,v)=min(au,av)(dep[u]+dep[v]−2×dep[lca(u,v)])min(a_u, a_v) dis(u, v) = min(a_u, a_v)\left(dep[u] + dep[v] - 2 \times dep[lca(u, v)]\right)\\ min(au​,av​)dis(u,v)=min(au​,av​)(dep[u]+dep[v]−2×dep[lca(u,v)])

如果考虑 dsu on tree,则是枚举uuu,分两种情况统计答案:

  • au≤ava_u \leq a_vau​≤av​,则∑v∈Sau(dep[u]+dep[v]−2×dep[lca(u,v)])\sum\limits_{v \in S} a_u(dep[u] + dep[v] - 2 \times dep[lca(u, v)])v∈S∑​au​(dep[u]+dep[v]−2×dep[lca(u,v)]),则我们只要知道集合SSS中有多少个点,以及∑v∈Sdep[v]\sum\limits_{v \in S} dep[v]v∈S∑​dep[v]即可,

    设点的个数为totaltotaltotal,∑v∈Sdep[v]=Sumdep\sum\limits_{v \in S} dep[v] = Sum_{dep}v∈S∑​dep[v]=Sumdep​,则上式等价于au×tatal×(dep[u]−2×dep[lca(u,v)])+au×Sumdepa_u \times tatal \times (dep[u] - 2 \times dep[lca(u, v)]) + a_u \times Sum_{dep}au​×tatal×(dep[u]−2×dep[lca(u,v)])+au​×Sumdep​。

  • au>ava_u > a_vau​>av​,则∑u∈Sav(dep[u]+dep[v]−2×dep[lca(u,v)])\sum\limits_{u \in S} a_v(dep[u] + dep[v] - 2 \times dep[lca(u, v)])u∈S∑​av​(dep[u]+dep[v]−2×dep[lca(u,v)]),则我们只要知道Sumav×dep[v]Sum_{a_v \times dep[v]}Sumav​×dep[v]​,以及SumavSum_{a_v}Sumav​​即可求得答案,

    上式等价于Sumav×dep[v]+Sumav×(dep[u]−2×dep[lca(u,v)])Sum_{a_v \times dep[v]} + Sum_{a_v} \times (dep[u] - 2 \times dep[lca(u, v)])Sumav​×dep[v]​+Sumav​​×(dep[u]−2×dep[lca(u,v)])。

所以可以对点权离散化,然后用线段树来维护上面需要的四个值,即可进行 dsu on tree,整体复杂度nlog⁡nlog⁡nn \log n \log nnlognlogn。

由于上面的统计我们都是进行的单向计算,所以还要对上述计算完后的答案乘以222即可。

#include <bits/stdc++.h>
#define ls rt << 1
#define rs rt << 1 | 1
#define mid (l + r >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, rusing namespace std;const int N = 2e5 + 10, mod = 998244353;int head[N], to[N << 1], nex[N << 1], cnt = 1;int son[N], sz[N], l[N], r[N], rk[N], dep[N], tot;int sum1[N << 2], sum2[N << 2], sum3[N << 2], sum4[N << 2];int a[N], b[N], n, m;inline int add(int x, int y) {return x + y < mod ? x + y : x + y - mod;
}inline int sub(int x, int y) {return x >= y ? x - y : x - y + mod;
}inline int mul(int x, int y) {return 1ll * x * y % mod;
}void Add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++;
}void dfs(int rt, int fa) {dep[rt] = dep[fa] + 1, sz[rt] = 1, l[rt] = ++tot, rk[tot] = rt;for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa) {continue;}dfs(to[i], rt);sz[rt] += sz[to[i]];if (!son[rt] || sz[to[i]] > sz[son[rt]]) {son[rt] = to[i];}}r[rt] = tot;
}void push_up(int rt) {sum1[rt] = add(sum1[ls], sum1[rs]);sum2[rt] = add(sum2[ls], sum2[rs]);sum3[rt] = add(sum3[ls], sum3[rs]);sum4[rt] = add(sum4[ls], sum4[rs]);
}void update(int rt, int l, int r, int x, int v, int op) {if (l == r) {if (op == 1) {sum1[rt] += 1, sum2[rt] = add(sum2[rt], v), sum3[rt] = add(sum3[rt], mul(b[x], v)), sum4[rt] = add(sum4[rt], b[x]);}else {sum1[rt] -= 1, sum2[rt] = sub(sum2[rt], v), sum3[rt] = sub(sum3[rt], mul(b[x], v)), sum4[rt] = sub(sum4[rt], b[x]);}return ;}if (x <= mid) {update(lson, x, v, op);}else {update(rson, x, v, op);}push_up(rt);
}int ans, ans1, ans2, ans3, ans4, ans5;void query(int rt, int l, int r, int L, int R) {if (l >= L && r <= R) {ans1 = add(ans1, sum1[rt]), ans2 = add(ans2, sum2[rt]), ans3 = add(ans3, sum3[rt]), ans4 = add(ans4, sum4[rt]);return ;}if (L <= mid) {query(lson, L, R);}if (R > mid) {query(rson, L, R);}
}void dfs(int rt, int fa, bool keep) {for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa || to[i] == son[rt]) {continue;}dfs(to[i], rt, 0);}if (son[rt]) {dfs(son[rt], rt, 1);}for (int i = head[rt]; i; i = nex[i]) {if (to[i] == fa || to[i] == son[rt]) {continue;}for (int j = l[to[i]]; j <= r[to[i]]; j++) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, a[rk[j]], m);ans = add(ans, mul(ans2, b[a[rk[j]]]));ans = add(ans, mul(b[a[rk[j]]], mul(ans1, sub(dep[rk[j]], 2 * dep[rt]))));if (a[rk[j]] != 1) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, 1, a[rk[j]] - 1);ans = add(ans, ans3);ans = add(ans, mul(ans4, sub(dep[rk[j]], 2 * dep[rt])));}}for (int j = l[to[i]]; j <= r[to[i]]; j++) {update(1, 1, m, a[rk[j]], dep[rk[j]], 1);}}ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, a[rt], m);ans = add(ans, mul(ans2, b[a[rt]]));ans = add(ans, mul(b[a[rt]], mul(ans1, sub(dep[rt], 2 * dep[rt]))));if (a[rt] != 1) {ans1 = ans2 = ans3 = ans4 = 0;query(1, 1, m, 1, a[rt] - 1);ans = add(ans, ans3);ans = add(ans, mul(ans4, sub(dep[rt], 2 * dep[rt])));}update(1, 1, m, a[rt], dep[rt], 1);if (!keep) {for (int i = l[rt]; i <= r[rt]; i++) {update(1, 1, m, a[rk[i]], dep[rk[i]], -1);}}
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d", &n);for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);b[i] = a[i];}sort(b + 1, b + 1 + n);m = unique(b + 1, b + 1 + n) - (b + 1);for (int i = 1; i <= n; i++) {a[i] = lower_bound(b + 1, b + 1 + m, a[i]) - b;}for (int i = 1, x, y; i < n; i++) {scanf("%d %d", &x, &y);Add(x, y);Add(y, x);}dfs(1, 0);dfs(1, 0, 1);printf("%d\n", mul(2, ans));return 0;
}

小 Q 与树(dsu on tree + segment tree)牛客练习赛 81 D相关推荐

  1. 牛客练习赛81 E. 小 Q 与函数求和 1( “简单莫比乌斯反演” ,欧拉函数性质)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 牛客练习赛81 E. 小 Q 与函数求和 1( "简单莫比乌斯反演" ) Prob ...

  2. 牛客练习赛81 B. 小 Q 与彼岸花(FWT nlogn做法)

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 Weblink https://ac.nowcoder.com/acm/contest/11171/B ...

  3. 小 Q 与函数求和 1(牛客练习赛 81 E)

    小 Q 与函数求和 1 ∑i=1n∑j=1nϕ(ijgcd⁡(i,j)K)∑i=1n∑j=1ngcd⁡(i,j)Kϕ(ij)∑i=1n∑j=1ngcd⁡(i,j)Kϕ(i)ϕ(j)gcd⁡(i,j)ϕ ...

  4. 牛客练习赛81 小Q与彼岸花 (分块+可持久化01trie)

    题意: 题解:因为这个题目是弱化以后的,正常的范围是5e4 . 看了官方题解去学习了一波可持久化01trie然后回来把这个题补完. 可持久数据结构其实就是我们的数据结构的内容会不断发生变化,而我们还要 ...

  5. 牛客练习赛34 - C little w and Segment Coverage(思维、树状数组)

    title: 牛客练习赛34 - C little w and Segment Coverage(思维.树状数组) date: 2018-12-15 16:36:55 tags: [树状数组,思维] ...

  6. 牛客练习赛73 D 离别(线段树+右端点排序离线查询)

    牛客练习赛73 D 离别 思路: 对于每一个固定的右端点i,我们都找到一个区间(l,r)使得区间中的点为左端点时 里面最大的的种数为k. 这个可以用队列或者vector来维护. 然后我们对于q个查询, ...

  7. 牛客练习赛84:牛客推荐系统开发之标签重复度(点分治+动态开点权值线段树)

    题意: 给你一棵树,问树上所有两点路径上的(最大值最小值乘积)之和. 题解: 很明显的一个点分治问题,然后就是个二维偏序问题了(虽然我也不知道啥是二维偏序). 点分治不难,重点是点分治内cal函数如何 ...

  8. 牛客练习赛33 D tokitsukaze and Inverse Number (树状数组求逆序对,结论)

    链接:https://ac.nowcoder.com/acm/contest/308/D 来源:牛客网 tokitsukaze and Inverse Number 时间限制:C/C++ 1秒,其他语 ...

  9. 牛客练习赛 4 A-Laptop (线段树,思维/GTMD普通前缀和也能求)

    链接:https://ac.nowcoder.com/acm/contest/16/A?&headNav=www 来源:牛客网 题目描述 FST是一名可怜的小朋友,他很强,但是经常fst,所以 ...

最新文章

  1. 深度学习在人脸检测中的应用 | CSDN 博文精选
  2. Java I/O模型从BIO到NIO和Reactor模式
  3. 数据包接收系列 — IP协议处理流程(一)
  4. mysql innodb_undo_directory默认_MySQL innodb_undo_tablespaces相关参数
  5. git 忽略文件 .gitignore 以及规则
  6. F5定时切换维护页面
  7. VB-VB.NET中 从字符串“XX”到类型“Double”的转换无效
  8. Spring Boot基础学习笔记19:自定义RedisTemplate与RedisCacheManager
  9. matlab 约束函数,【优化求解】MATLAB约束优化之惩罚函数法
  10. C语言size_t类型
  11. Netflix如何设计一个能满足5倍增长量的时序数据存储新架构?
  12. Web前端开发之“常见模块你真的很了解吗?”
  13. mysql的sererdata_MySQL_win2008 R2服务器下修改MySQL 5.5数据库data目录的方法,说明: 操作系统:Windows Server - phpStudy...
  14. 微信小程序远程git代码管理
  15. 图像处理-RGB24转YUV420遇到的坑以及执行效率对比
  16. 高斯勒让德求积公式matlab通用程序,MATLAB软件及高斯勒让德求积公式.doc
  17. GB/T28181之国标编码一览表,需要自取
  18. 26个大小写字母对应的哈希值
  19. c 循序结构程序设计
  20. 脉脉行业头条业务的思路猜想

热门文章

  1. js监听地址栏变化_vue中本地储存也可以实时监听
  2. java程序结构_java程序结构
  3. 神抓拍!2020搞笑野生动物摄影大赛,哈哈哈哈哈笑到头掉
  4. 这9个人气超高的公众号,你还没关注吗?
  5. Java常用类集接口以及实现方式总结
  6. python根据地址查看变量名_tensorflow创建变量以及根据名称查找变量
  7. mysql innodb事务中_MySQL InnoDB如何保证事务特性示例详解
  8. java虚拟机工作原理图_Java虚拟机工作原理
  9. android studio初始化设置,Android studio 初始设置
  10. python elasticsearch查询_python 查询Elasticsearch的小例子