【线段树合并/树上差分】P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并

思路

对 \(x,y,lca(u,v),fa_{lca(u,v)}\) 四个点进行树上差分,然后用线段树合并动态权值线段树。

#include <bits/stdc++.h>

using namespace std;

using i64 = long long;

template<class Node>
struct PersidentSegmentTree {
#define lc(u) tr[u].l
#define rc(u) tr[u].r
const int n;
int tot = 0;
vector<Node> tr;
vector<int> root; PersidentSegmentTree(): n(0) {} PersidentSegmentTree(int n_): n(n_) {
int N = (n << 6) + 10;
tr.reserve(N); root.reserve(N);
tr.resize(N); root.resize(N);
} PersidentSegmentTree(vector<int>& a): PersidentSegmentTree(a.size() - 1) {
function<void(int&, int, int)> build = [&](int& now, int l, int r) {
now = ++ tot;
if (l == r) {
return ;
}
int m = (l + r) >> 1;
build(lc(now), l, m);
build(rc(now), m + 1, r);
};
build(root[0], 1, n);
} //上传
void pushup(int u) {
if (tr[lc(u)].Sum >= tr[rc(u)].Sum) {
tr[u].Sum = tr[lc(u)].Sum;
tr[u].pos = tr[lc(u)].pos;
} else {
tr[u].Sum = tr[rc(u)].Sum;
tr[u].pos = tr[rc(u)].pos;
}
} //动态开点/更新树结点
void insert(int& now, int l, int r, int pos, int w) {
if (!now)
now = ++ tot; if (l == r) {
tr[now].Sum += w;
tr[now].pos = pos;
return;
} int m = l + r >> 1;
if (pos <= m)
insert(lc(now), l, m, pos, w);
else
insert(rc(now), m + 1, r, pos, w);
pushup(now);
} //开新前缀树,last代表前缀,now代表新树根
void insert(int& now, int last, int l, int r, int pos, int w) {
now = ++ tot;
tr[now] = tr[last];
if (l == r) {
return;
}
int m = l + r >> 1;
if (pos <= m)
insert(lc(now), lc(last), l, m, pos, w);
else
insert(rc(now), rc(last), m + 1, r, pos, w);
} //单点
int query(int now, int l, int r, int pos) {
if (l == r) {
return tr[now].Sum;
} int m = l + r >> 1;
if (pos <= m)
return query(lc(now), l, m, pos);
else
return query(rc(now), m + 1, r, pos);
} //区间查询 [u,v]->[root[l-1],root[r]]
int query(int u, int v, int l, int r, int pos) {
if (l == r) {
return tr[u].Sum;
} int m = l + r >> 1;
if (pos <= m)
return query(lc(u), lc(v), l, m, pos);
else
return query(rc(u), rc(v), m + 1, r, pos);
} void merge(int &u, int v, int l, int r) {
if (!u || !v) {
u = u + v;
return;
} if (l == r) {
tr[u].Sum += tr[v].Sum;
return ;
} int m = l + r >> 1;
merge(lc(u), lc(v), l, m);
merge(rc(u), rc(v), m + 1, r);
pushup(u);
}
}; struct Node {
int l, r;
int Sum = 0, pos = 0;
}; constexpr int N = 1e5 + 10, M = N - 10, logn = 20;
PersidentSegmentTree<Node> pst(N); int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr); int n, m;
cin >> n >> m; vector g(n + 1, vector<int>());
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >> v;
g[u].emplace_back(v);
g[v].emplace_back(u);
} vector dep(n + 1, 0);
vector f(n + 1, vector<int>(logn + 1)); auto dfs = [&](auto && self, int u, int fa)->void{
f[u][0] = fa;
dep[u] = dep[fa] + 1;
for (int i = 1; i <= logn; i ++) {
f[u][i] = f[f[u][i - 1]][i - 1];
}
for (auto v : g[u]) {
if (v == fa)continue;
self(self, v, u);
}
}; dfs(dfs, 1, 0); auto lca = [&](int u, int v)->int{
if (dep[u] < dep[v])
swap(u, v); for (int i = logn; i >= 0 ; i --) {
if (dep[f[u][i]] >= dep[v]) {
u = f[u][i];
}
} if (u == v)
return u; for (int i = logn; i >= 0; i --) {
if (f[u][i] != f[v][i]) {
u = f[u][i], v = f[v][i];
}
} return f[u][0];
}; while (m --) {
int x, y, z;
cin >> x >> y >> z;
int k = lca(x, y);
pst.insert(pst.root[x], 1, M, z, 1);
pst.insert(pst.root[y], 1, M, z, 1);
pst.insert(pst.root[k], 1, M, z, -1);
pst.insert(pst.root[f[k][0]], 1, M, z, -1);
} vector<int> ans(n + 1);
auto calc = [&](auto && self, int u, int fa)->void{
for (auto v : g[u]) {
if (v == fa) continue;
self(self, v, u);
pst.merge(pst.root[u], pst.root[v], 1, M);
}
ans[u] = pst.tr[pst.root[u]].pos;
if (!pst.tr[pst.root[u]].Sum) ans[u] = 0;
}; calc(calc, 1, 0); for (int i = 1; i <= n; i ++)
cout << ans[i] << "\n"; return 0;
}

【线段树合并/树上差分】[P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并的更多相关文章

  1. P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)

    P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...

  2. P4556 [Vani有约会]雨天的尾巴 (线段树合并)

    P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...

  3. P4556 [Vani有约会]雨天的尾巴(线段树合并)

    传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...

  4. [题解] P4556 [Vani有约会]雨天的尾巴

    [题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...

  5. 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告

    P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...

  6. 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)

    传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...

  7. P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)

    显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...

  8. P4556 [Vani有约会]雨天的尾巴

    目录 思路 优化 过程中的问题/疑问 错误 代码 思路 每个节点维护一课线段树(当然是动态开点) 线段树的作用是统计这个节点有多少种粮食型号,以及最多的粮食型号 然后树上差分,u和v点 +1,lca( ...

  9. 洛咕 P4556 [Vani有约会]雨天的尾巴

    终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...

  10. 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)

    题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...

随机推荐

  1. 【踩坑】.NET 8.0 自定义IExceptionHandler不生效

    中间件实现异常处理 在ASP.NET Core里,我们可以使用中间件(Middleware)实现全局的异常处理. 如内置的异常处理中间件 UseExceptionHandler app.UseExce ...

  2. Asp.net core Swashbuckle Swagger 的常用配置

    背景 .net core Swashbuckle Swagger 官方文档:https://github.com/domaindrivendev/Swashbuckle.AspNetCore 我们发现 ...

  3. poj1338 ugly number 题解 打表

    类似的题目有HDU1058 humble number(翻译下来都是丑陋的数字). Description Ugly numbers are numbers whose only prime fact ...

  4. 如何设置 QEMU 输出到控制台并使用 Shell 脚本自动化

    如何设置 QEMU 输出到控制台并使用 Shell 脚本自动化 原文:How to Setup QEMU Output to Console and Automate Using Shell Scri ...

  5. Nuxt3 的生命周期和钩子函数(五)

    title: Nuxt3 的生命周期和钩子函数(五) date: 2024/6/29 updated: 2024/6/29 author: cmdragon excerpt: 摘要:本文详细介绍了Nu ...

  6. 牛客小白月赛97 A-D题解

    AAAAAAAAAAAAAAAAAAAAA -----------------------------题解------------------------------------------- 统计数 ...

  7. 【ClickHouse】5:clickhouse集群部署

    背景介绍: 有三台CentOS7服务器安装了ClickHouse HostName IP 安装程序 程序端口 centf8118.sharding1.db 192.168.81.18 clickhou ...

  8. 机器学习策略篇:详解如何使用来自不同分布的数据,进行训练和测试(Training and testing on different distributions)

    如何使用来自不同分布的数据,进行训练和测试 深度学习算法对训练数据的胃口很大,当收集到足够多带标签的数据构成训练集时,算法效果最好,这导致很多团队用尽一切办法收集数据,然后把它们堆到训练集里,让训练的 ...

  9. Netcode for Entities里如何对Ghost进行可见性筛选(1.2.3版本)

    一行代码省流:SystemAPI.GetSingleton() 当你需要按照区域.距离或者场景对Ghost进行筛选的时候,Netcode for Entities里并没有类似FishNet那样方便的过 ...

  10. ping和tcping的区别

    ping是简单的测试网络连接情况的小命令,但是ping无法直接ping端口.某些网站还防ping,tcping工具也是通过ping来测试但是他能看端口是否打开