【线段树合并/树上差分】[P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
【线段树合并/树上差分】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有约会] 雨天的尾巴 /【模板】线段树合并的更多相关文章
- P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)
P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...
- P4556 [Vani有约会]雨天的尾巴 (线段树合并)
P4556 [Vani有约会]雨天的尾巴 题意: 首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋 ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并)
传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...
- [题解] P4556 [Vani有约会]雨天的尾巴
[题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...
- 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)
传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- P4556 [Vani有约会]雨天的尾巴
目录 思路 优化 过程中的问题/疑问 错误 代码 思路 每个节点维护一课线段树(当然是动态开点) 线段树的作用是统计这个节点有多少种粮食型号,以及最多的粮食型号 然后树上差分,u和v点 +1,lca( ...
- 洛咕 P4556 [Vani有约会]雨天的尾巴
终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
随机推荐
- uniapp 使用z-paging 分页组件 写在头部插槽内的单选按钮无法点击
这个问题是因为组件层级太低 <z-paging ref="paging" v-model="dataList" @query="queryLis ...
- OSI七层网络模型和TCP/IP四层模型
OSI七层网络模型 OSI: 开放系统互连参考模型是ISO制定的一个用于计算机或通信系统间互联的标准体系 OSI七层模型功能: 物理层: 七层模型的最底层,主要是物理介质传输媒介(网线或者无线),在不 ...
- Spring之webMvc异常处理
异常处理可以前端处理,也可以后端处理. 从稳妥的角度出发,两边都应该进行处理. 本文专门阐述如何在服务端进行http请求异常处理. 一.常见的异常类型 当我们做http请求的时候,会有各种各样的可能错 ...
- mysqldump备份时保持数据一致性分析--master-data=2 --single-transaction
对MySQL数据进行备份,常见的方式如以下三种,可能有很多人对备份时数据一致性并不清楚 1.直接拷贝整个数据目录下的所有文件到新的机器.优点是简单.快速,只需要拷贝:缺点也很明显,在整个备份过程中新机 ...
- 卷积神经网络中nn.Conv2d()和nn.MaxPool2d()以及卷积神经网络实现minist数据集分类
卷积神经网络中nn.Conv2d()和nn.MaxPool2d() 卷积神经网络之Pythorch实现: nn.Conv2d()就是PyTorch中的卷积模块 参数列表 参数 作用 in_channe ...
- C#使用Aspose将Word\HTML 转换成PDF文件
写在前面 Aspose 这个是收费的,直接使用是有水印的 需要用到的dll文件 ==> Aspose.Words.dll.Aspose.HTML.dll.Aspose.Total.lic(授权文 ...
- ubuntu18 编译安装gccxml
最近需要在ubuntu上安装gccxml,我的ubuntu版本是18. 使用sudo apt-get install gccxml提示找不到gccxml,最后使用了编译安装的方式安装gccxml. 1 ...
- Unity 2023/Unity 6编辑器文字模糊的解决方案
这是从2023.1开始就有的问题了.本质原因是Unity不知道哪个天才决定的在编辑器文字上使用了SDF渲染. 2023.1因为缺乏选项导致几乎不可用:2023.2加了一个锐度选项:后来在论坛里被众人喷 ...
- 基于Java+Spring+Vue仓储出入库管理系统设计和实现
\n文末获取源码联系 感兴趣的可以先收藏起来,大家在毕设选题,项目以及论文编写等相关问题都可以给我加好友咨询 系统介绍: 网络的广泛应用给生活带来了十分的便利.所以把仓储出入库管理与现在网络相结合,利 ...
- 一文全懂:独立冗余磁盘阵列(RAID)
独立冗余磁盘阵列,也就是大家常说的RAID,英文全称是:Redundant Array of Independent Disks,使用该技术,可以大幅提高硬盘设备的 IO 读写速度,还存在数种数据冗余 ...