「Luogu4556」Vani有约会-雨天的尾巴

传送门

很显然可以考虑树上差分+桶,每次更新一条链就是把这条链上的点在桶对应位置打上 \(1\) 的标记,

最后对每个点取桶中非零值的位置作为答案即可,如果全都是 \(0\) 就输出 \(0\) ,这样的时间复杂度和空间复杂度都是 \(O(nm)\)

考虑优化这一个算法:

我们考虑用权值线段树来代替桶

我们可以考虑用树剖的方式来更新一条链,那么就变成了每次在值域线段树上对 \(\log\) 段区间差分,

需要注意的是,我们把正标记打在深度低的那一边,因为我们可以这样按照 \(\text{dfs}\) 序算答案

小小的证明:

  • 对于不贡献当前点的询问,这样做显然是没有影响的
  • 对于贡献当前点的询问,它的贡献一定回被重链的顶点打好标记,也一定会被重链底的轻儿子消除

这样一来就得到了一种类似于离线算法的统计答案方法,于是,线段树也就只要开一棵

代码:

#include <cstdio>
#include <vector>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
using namespace std;
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} const int _ = 1e5 + 5; int tot, head[_], nxt[_ << 1], ver[_ << 1];
inline void Add_edge(int u, int v)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v; } int n, m, ans[_]; vector < int > vec[_];
int dep[_], siz[_], son[_], fa[_];
int dfn[_], rev[_], top[_];
struct node { int mx, pos; } t[_ << 2]; inline int lc(int p) { return p << 1; } inline int rc(int p) { return p << 1 | 1; } inline void pushup(int p) {
if (t[lc(p)].mx >= t[rc(p)].mx)
t[p].mx = t[lc(p)].mx, t[p].pos = t[lc(p)].pos;
else
t[p].mx = t[rc(p)].mx, t[p].pos = t[rc(p)].pos;
} inline void build(int p = 1, int l = 1, int r = 100000) {
if (l == r) { t[p].mx = 0, t[p].pos = l; return ; }
int mid = (l + r) >> 1;
build(lc(p), l, mid), build(rc(p), mid + 1, r), pushup(p);
} inline void update(int x, int v, int p = 1, int l = 1, int r = 100000) {
if (l == r) { t[p].mx += v; return ; }
int mid = (l + r) >> 1;
if (x <= mid) update(x, v, lc(p), l, mid);
else update(x, v, rc(p), mid + 1, r);
pushup(p);
} inline void uptRange(int x, int y, int z) {
int fx = top[x], fy = top[y];
while (fx != fy) {
if (dep[fx] < dep[fy]) swap(x, y), swap(fx, fy);
vec[dfn[fx]].push_back(z), vec[dfn[x] + 1].push_back(-z);
x = fa[fx], fx = top[x];
}
if (dep[x] > dep[y]) swap(x, y);
vec[dfn[x]].push_back(z), vec[dfn[y] + 1].push_back(-z);
} inline void dfs(int u, int f) {
siz[u] = 1, dep[u] = dep[f] + 1, fa[u] = f;
for (rg int i = head[u]; i; i = nxt[i]) {
int v = ver[i]; if (v == f) continue;
dfs(v, u), siz[u] += siz[v];
if (siz[v] > siz[son[u]]) son[u] = v;
}
} inline void dfs(int u, int f, int topf) {
top[rev[dfn[u] = ++dfn[0]] = u] = topf;
if (son[u]) dfs(son[u], u, topf);
for (rg int i = head[u]; i; i = nxt[i]) {
int v = ver[i]; if (v == f || v == son[u]) continue;
dfs(v, u, v);
}
} int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n), read(m);
for (rg int u, v, i = 1; i < n; ++i)
read(u), read(v), Add_edge(u, v), Add_edge(v, u);
dfs(1, 0), dfs(1, 0, 1), build();
for (rg int x, y, z; m--; ) read(x), read(y), read(z), uptRange(x, y, z);
for (rg int i = 1; i <= n; ++i) {
for (rg int j : vec[i]) if (j > 0) update(j, 1); else update(-j, -1);
ans[rev[i]] = t[1].mx > 0 ? t[1].pos : 0;
}
for (rg int i = 1; i <= n; ++i) printf("%d\n", ans[i]);
return 0;
}

「Luogu4556」Vani有约会-雨天的尾巴的更多相关文章

  1. [Vani有约会]雨天的尾巴 线段树合并

    [Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...

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

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

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

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

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

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

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

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

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

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

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

    嘟嘟嘟 看到链上操作,自然想到树剖. 先考虑序列上的问题:那么区间修改可以用差分.所以我们把操作拆成\(L\)和\(R + 1\)两个点,然后离线.排序后扫一遍,用线段树维护数量最多的颜色是哪一个. ...

  8. [Vani有约会]雨天的尾巴(树上差分+线段树合并)

    首先村落里的一共有n座房屋,并形成一个树状结构.然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮. 然后深绘里想知道,当所有的救济粮 ...

  9. 洛谷4556 [Vani有约会]雨天的尾巴

    原题链接 每个点开一个权值线段树,然后用树上差分的方法修改,最后自底向上暴力线段树合并即可. 不过空间较大,会\(MLE\),写个内存池就可以了. #include<cstdio> #in ...

随机推荐

  1. Spring Boot框架 - 数据访问 - JDBC&自动配置

    一.新建Spring Boot 工程 特殊勾选数据库相关两个依赖 Mysql Driver — 数据库驱动 Spring Data JDBC 二.配置文件application.properties ...

  2. Go标准库之Log

      文章引用自 Go语言标准库log介绍 无论是软件开发的调试阶段还是软件上线之后的运行阶段,日志一直都是非常重要的一个环节,我们也应该养成在程序中记录日志的好习惯. log Go语言内置的log包实 ...

  3. IDEA Tomcat配置 VM Option

    -server -XX:PermSize=512M -XX:MaxPermSize=1024m -Dfile.encoding=UTF-8

  4. 《Web安全攻防 渗透测试实战指南》 学习笔记 (二)

    Web安全攻防 渗透测试实战指南   学习笔记 (二)   第二章  漏洞环境及实践  

  5. centosflask+uWSGI+nginx部署

    centosflask+uWSGI+nginx部署 1.      概念 Flask自带webserver--Werkzeug,可以搭建服务,运行网站.但在开发时,一般会用专业的--uWSGI. 另外 ...

  6. 寒假pta一

    打印沙漏 本题要求你写个程序把给定的符号打印成沙漏的形状.例如给定17个“*”,要求按下列格式打 ***** *** * *** ***** 所谓“沙漏形状”,是指每行输出奇数个符号:各行符号中心对齐 ...

  7. 02-13Android学习进度报告十三

    今天我学习了ListView之checkbox错位问题解决.感觉还是很麻烦的. 好的存储这个Checkbox的方法有很多,你可以放到一个HashMap<Integer, Boolean>中 ...

  8. 电源适配器DC插头规格

    电源适配器 DC 插头的内径外径规格有 (单位为 MM) :2.0*0.72.35*0.72.35*1.12.5*0.73.5*1.13.5*1.354.0*1.75.5*2.15.5*2.54.75 ...

  9. bat获取当前路径

    @echo off setlocal EnableDelayedExpansion echo 当前正在运行的批处理文件所在路径:!cd! pause @echo off echo 当前目录是:%cd% ...

  10. python闯关之路一(语法基础)

      1,什么是编程?为什么要编程? 答:编程是个动词,编程就等于写代码,那么写代码是为了什么呢?也就是为什么要编程呢,肯定是为了让计算机帮我们搞事情,代码就是计算机能理解的语言. 2,编程语言进化史是 ...