树上数据结构问题

news/2024/11/17 14:47:48/文章来源:https://www.cnblogs.com/libohan/p/18426652

天天爱跑步

假设现在又一棵树
image
如果一个人要从 \(3\) 跑到 \(5\),那么如果在 \(2\) 点的观察员要满足 \(w[2] = dep[2] - dep[3]\),如果在点 \(4\) 的观察员要满足 \(w[4] = dep[fa[lca]] - dep[3] + dep[lca] - dep[4]\),简单来说就是如果处于 \(i\) 点的观察员可以观察到,那么要满足 \(w[j] = dep[j] - dep[a]\)\(w[i] = dep[fa[lca]] - dep[a] + dep[lca] - dep[b]\),那么我们可以在点 \(a\)\(lca\) 的链上打个为 \(dep[i] - dep[a]\) 标记,然后在 \(b\)\(son[lca]\) 的链上打个为 \(dep[fa[lca]] - dep[a] + dep[lca] - dep[b]\) 的标记,然后用类似于差分和树上启发式合并即可

#include <bits/stdc++.h>using namespace std;const int N = 3e5 + 5;int n, m, w[N], s[N], t[N], dep[N], dp[N][25], ans[N], fa[N], lc[N];vector<int> g[N], sum[N];map<int, int> cnt[3][N];void dfs1(int u, int f) {dep[u] = dep[f] + 1;dp[u][0] = f;fa[u] = f;for (int i = 1; (1 << i) <= dep[u]; i++) {dp[u][i] = dp[dp[u][i - 1]][i - 1];}for (auto v : g[u]) {if (v == f) {continue;}dfs1(v, u);}
}int lca(int a, int b) {if (dep[a] > dep[b]) {swap(a, b);}for (int i = 20; i >= 0; i--) {if (dep[dp[b][i]] >= dep[a]) {b = dp[b][i];}}if (a == b) {return a;}for (int i = 20; i >= 0; i--) {if (dp[a][i] != dp[b][i]) {a = dp[a][i];b = dp[b][i];}}return dp[a][0];
}void dfs(int u, int f) {for (auto v : g[u]) {if (v == f) {continue;}dfs(v, u);for (auto p : {1, 2}) {if (cnt[p][v].size() > cnt[p][u].size()) {swap(cnt[p][v], cnt[p][u]);}for (auto cur : cnt[p][v]) {cnt[p][u][cur.first] += cur.second;}}}ans[u] = cnt[1][u][dep[u] + w[u]] + cnt[2][u][w[u] - dep[u]];
}int main() {cin >> n >> m;for (int i = 1, u, v; i < n; i++) {cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}dfs1(1, 0);for (int i = 1; i <= n; i++) {cin >> w[i];}for (int i = 1; i <= m; i++) {cin >> s[i] >> t[i];int lc = lca(s[i], t[i]);int dis = dep[s[i]] + dep[t[i]] - 2 * dep[lc];cnt[1][s[i]][dep[s[i]]]++;cnt[1][fa[lc]][dep[s[i]]]--;cnt[2][t[i]][dis - dep[t[i]]]++;cnt[2][lc][dis - dep[t[i]]]--;}dfs(1, 0);for (int i = 1; i <= n; i++) {cout << ans[i] << " ";}return 0;
}

Sum of Tree Distance

虚树和一个简单的树形 \(dp\) 即可,虚树就是建出一个 \(a_i\) 全部相同的数,这样就变得非常好处理

#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 3e5 + 5;struct node {int v, w;
};int n, a[N], dep[N], dfn[N], dcnt, dp[N][25], ans, sz[N], stk[N], x, vis[N];vector<int> g[N], v[N];vector<node> new_g[N];void dfs1(int u, int f) {dfn[u] = ++dcnt;dep[u] = dep[f] + 1;dp[u][0] = f;v[a[u]].push_back(u);for (int i = 1; (1 << i) <= dep[u]; i++) {dp[u][i] = dp[dp[u][i - 1]][i - 1];}for (auto v : g[u]) {if (v == f) {continue;}dfs1(v, u);}
}int lca(int a, int b) {if (dep[a] > dep[b]) {swap(a, b);}for (int i = 20; i >= 0; i--) {if (dep[dp[b][i]] >= dep[a]) {b = dp[b][i];}}if (a == b) {return a;}for (int i = 20; i >= 0; i--) {if (dp[a][i] != dp[b][i]) {a = dp[a][i];b = dp[b][i];}}return dp[a][0];
}void dfs(int u, int f) {sz[u] = (a[u] == x);for (auto e : new_g[u]) {if (e.v == f) {continue;}dfs(e.v, u);sz[u] += sz[e.v];}
}void dfs2(int u, int f) {for (auto e : new_g[u]) {if (e.v == f) {continue;}ans += e.w * (sz[1] - sz[e.v]) * sz[e.v];if (u == 1) {//cout << e.w << " " << sz[1] << " " << sz[e.v] << "\n";}dfs2(e.v, u);}
}void clean(int u, int f) {sz[u] = 0;for (auto e : new_g[u]) {if (e.v == f) {continue;}clean(e.v, u);}new_g[u].clear();
}void build() {int top = 1;stk[top] = 1;for (auto cur : v[x]) {if (cur == 1) {continue;}int l = lca(cur, stk[top]);if (l != stk[top]) {while (dfn[l] < dfn[stk[top - 1]]) {new_g[stk[top - 1]].push_back({stk[top], abs(dep[stk[top - 1]] - dep[stk[top]])});new_g[stk[top]].push_back({stk[top - 1], abs(dep[stk[top - 1]] - dep[stk[top]])});top--;}if (dfn[l] > dfn[stk[top - 1]]) {new_g[l].push_back({stk[top], abs(dep[l] - dep[stk[top]])});new_g[stk[top]].push_back({l, abs(dep[l] - dep[stk[top]])});stk[top] = l;}else {new_g[l].push_back({stk[top], abs(dep[l] - dep[stk[top]])});new_g[stk[top]].push_back({l, abs(dep[l] - dep[stk[top]])});top--;}}stk[++top] = cur;}for (int i = 1; i < top; i++) {new_g[stk[i]].push_back({stk[i + 1], abs(dep[stk[i]] - dep[stk[i + 1]])});new_g[stk[i + 1]].push_back({stk[i], abs(dep[stk[i]] - dep[stk[i + 1]])});}dfs(1, 0);dfs2(1, 0);clean(1, 0);
}signed main() {cin >> n;for (int i = 1, u, v; i < n; i++) {cin >> u >> v;g[u].push_back(v);g[v].push_back(u);}for (int i = 1; i <= n; i++) {cin >> a[i];}dfs1(1, 0);for (int i = 1; i <= n; i++) {if (!vis[a[i]]) {x = a[i];vis[x] = true;build();}}cout << ans;return 0;
}

Happy Life in University

我们可以先预处理初对于 \(i\) 节点来说的每个子树内的第一个与他 \(p\) 相等的 \(j\) 存在一个集合里,然后从下往上做操作,对于一个点 \(i\),先将他的集合内的数的子树都加上一个 \(-1\),然后将 \(i\) 的子树全部加上 \(1\) 即可

#include <bits/stdc++.h>using namespace std;#define int long longconst int N = 3e5 + 5;int t, n, a[N], tr[N * 4], lazy[N * 4], dfn[N], dcnt, sz[N], ans, cnt, b[N];vector<int> g[N], tmp[N];stack<int> stk[N];void pushdown(int i, int l, int r) {tr[i * 2] += lazy[i];lazy[i * 2] += lazy[i];tr[i * 2 + 1] += lazy[i];lazy[i * 2 + 1] += lazy[i];lazy[i] = 0;
}void modify(int i, int l, int r, int x, int y, int k) {if (l > y || r < x) {return ;}if (l >= x && r <= y) {tr[i] += k;lazy[i] += k;return ;}int mid = (l + r) >> 1;pushdown(i, l, r);modify(i * 2, l, mid, x, y, k);modify(i * 2 + 1, mid + 1, r, x, y, k);tr[i] = max(tr[i * 2], tr[i * 2 + 1]);
}int query(int i, int l, int r, int x, int y) {if (l > y || r < x) {return 0;}if (l >= x && r <= y) {return tr[i];}int mid = (l + r) >> 1;pushdown(i, l, r);return max(query(i * 2, l, mid, x, y), query(i * 2 + 1, mid + 1, r, x, y));
}void build(int i, int l, int r) {if (l == r) {tr[i] = 0;lazy[i] = 0;return ;}int mid = (l + r) >> 1;build(i * 2, l, mid);build(i * 2 + 1, mid + 1, r);tr[i] = 0, lazy[i] = 0;
}void dfs1(int u, int f) {dfn[u] = ++dcnt;sz[u] = 1;if (!stk[a[u]].empty()) {tmp[stk[a[u]].top()].push_back(u);}stk[a[u]].push(u);for (auto v : g[u]) {if (v == f) {continue;}dfs1(v, u);sz[u] += sz[v];}stk[a[u]].pop();
}void dfs(int u, int f) {int maxi1 = 0, maxi2 = 0;for (auto v : g[u]) {if (v == f) {continue;}dfs(v, u);}for (auto cur : tmp[u]) {modify(1, 1, n, dfn[cur], dfn[cur] + sz[cur] - 1, -1);}modify(1, 1, n, dfn[u], dfn[u] + sz[u] - 1, 1);cnt = 2;b[1] = b[2] = 1;for (auto v : g[u]) {if (v == f) {continue;}int x = query(1, 1, n, dfn[v], dfn[v] + sz[v] - 1);b[++cnt] = x;}sort(b + 1, b + cnt + 1);ans = max({ans, b[cnt] * b[cnt - 1]});
}void Solve() {cin >> n;for (int i = 2, v; i <= n; i++) {cin >> v;g[i].push_back(v);g[v].push_back(i);}build(1, 1, n);for (int i = 1; i <= n; i++) {cin >> a[i];}dfs1(1, 0);dfs(1, 0);cout << ans << "\n";for (int i = 1; i <= n; i++) {g[i].clear();tmp[i].clear();}for (int i = 1; i <= n; i++) {while (!stk[i].empty()) {stk[i].pop();}}dcnt = 0;ans = 0;
}signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> t;while (t--) {Solve();}return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/802089.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

为什么网站连接数据库失败?

网站连接数据库失败通常是由以下几个主要原因造成的:数据库凭据错误:如果数据库用户名、密码或主机名错误,网站将无法建立数据库连接。请检查wp-config.php文件中的数据库连接信息是否正确。数据库服务器故障:数据库服务器宕机或无法访问也会导致连接失败。检查数据库服务是…

mqtt网关数据接入rabbitmq,缓存离线数据,实现消息保留

应用场景:网关将设备数据发布至mqtt服务器后,数采程序因为重启或者升级等原因,未能接到到离线的订阅消息,利用rabbitmq-mqtt可将离线数据缓存,待上线后接收启用mqtt插件 rabbitmq-plugins enable rabbitmq_mqtt qq:505645074

WordPress网站遇到“数据库连接错误”报错解决方法

当遇到WordPress网站出现“数据库连接错误”时,可以通过以下步骤来逐步排查和解决问题: 1. 确认数据库连接信息用户名和密码:确保数据库用户名和密码正确无误。 服务器地址:确认数据库服务器地址(通常是localhost,但也可能是其他地址)正确无误。2. 检查 wp-config.php 文…

clickhouse压测

Clickhouse压测 压测工具:jemter服务器监控脚本sql准备:简单sqlselect * from tb_plan_student where plan_id=1122980766105344 and region_id=330302 limit 10简单sql---部分字段select student_id,student_name from tb_plan_student where plan_id=1122980766105344 and…

国产化:TongRDS替代Redis

背景: 国产化要求,内存数据缓存中间件要换国产产品,这里简单记录一下替换过程,项目是 spring boot 微服务结构。官方文档比较全,这里只是个人记录的最简化的版本。1 安装 企业版 TongRDS 分为2个节点,我拿到的版本就是企业版,所以下面的都默认是企业版。分为中心节点和服…

阿里云mysql数据库服务器错误怎么回事

阿里云MySQL数据库服务器错误可能由多种因素造成,以下是一些常见的原因及解决方法:网络配置错误:检查服务器的网络配置,确保防火墙设置允许来自客户端的连接请求。 确认IP地址或域名解析正确,且客户端能够通过网络访问到数据库服务器。MySQL服务未启动:确认MySQL服务已经…

数据库连接错误:原因与解决方案

数据库连接错误可能由多种因素引起,下面列出了一些常见的原因及其解决方案: 常见原因及解决方案配置错误原因:数据库连接字符串中的参数错误,如主机名/IP地址、端口号、数据库名称、用户名或密码不正确。 解决方法:检查并确认连接字符串中的所有参数都正确无误。网络问题原…

淘宝商品评论API:电商数据的宝库

淘宝商品评论API是淘宝开放平台提供的一项服务,它允许开发者获取商品的用户评价信息,包括评分、评论文本、图片和视频等。这些数据对于商家来说是一个宝贵的资源,因为它们直接反映了消费者的真实感受和需求。实时分析用户反馈的重要性 提升客户满意度:通过实时分析用户反馈…

2 用户注册

创建用户模块应用在apps包下创建子应用 users python ../manage.py startapp users注册模块应用 INSTALLED_APPS=[ ... apps.users ]

Docker nsenter 命令使用以及lsns命令(需要安装utrace包)

查看容器对应宿主机上面的pid,容器技术的实质是进程,并没有完整的操作系统,就相当于在主机上面fork了一个子进程,通过docker daemon去fork一个子进程,这个子进程是可以在主机上面看到其pid的。 $ docker inspect -f {{.State.Pid}} 容器名或者容器id 如下:$ docker insp…

ubuntu离线安装docker

下载对应的包 https://download.docker.com/linux/ubuntu/dists/jammy/pool/stable/amd64/ 执行命令dpkg -i containerd.io_1.7.21-1_amd64.debdpkg -i docker-buildx-plugin_0.16.2-1~ubuntu.22.04~jammy_amd64.debdpkg -i docker-ce_27.2.0-1~ubuntu.22.04~jammy_amd64.debd…