P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案。
用动态开点的方式建立线段树,注意离散化。
1 #include<bits/stdc++.h>
2 using namespace std;
3 const int N = 1e5 + 10;
4 struct node {
5 int lc, rc, dat, pos;//dat记录最多的物品的次数,pos记录位置
6 }tr[N * 20 * 4];
7 int head[N], to[N << 1], nxt[N << 1], tot;
8 int n, m, num, cnt, t, ans[N];
9 int d[N], st[N][20], rt[N], X[N], Y[N], Z[N], val[N];
10 inline int read() {
11 int x = 0,f = 1;char ch = getchar();
12 while (ch<'0' || ch>'9') { if(ch == '-') f = -1;ch = getchar(); }
13 while (ch >= '0'&&ch <= '9') x = x * 10 + ch - '0',ch = getchar();
14 return x * f;
15 }
16 void add(int x, int y) {
17 nxt[++tot] = head[x];
18 head[x] = tot;
19 to[tot] = y;
20 }
21
22 void dfs(int u, int f) {
23 for (int i = head[u]; i; i = nxt[i]) {
24 int v = to[i];
25 if (d[v]) continue;
26 d[v] = d[u] + 1;
27 st[v][0] = u;
28 for (int j = 1; j <= t; j++)
29 st[v][j] = st[st[v][j-1]][j-1];
30 dfs(v, u);
31 }
32 }
33
34 int lca(int x, int y) {
35 if (d[x] > d[y]) swap(x, y);
36 for (int i = t; i >= 0; i--)
37 if (d[st[y][i]] >= d[x]) y = st[y][i];
38 if (x == y) return x;
39 for (int i = t; i >= 0; i--)
40 if (st[x][i] != st[y][i]) x = st[x][i], y = st[y][i];
41 return st[x][0];
42 }
43
44 void insert(int p, int l, int r, int val, int k) {
45 if (l == r) {
46 tr[p].dat += k;
47 tr[p].pos = tr[p].dat ? l : 0;
48 return ;
49 }
50 int mid = (l + r) >> 1;
51 if(val <= mid) {
52 if (!tr[p].lc) tr[p].lc = ++num;//动态开点
53 insert(tr[p].lc, l, mid, val, k);
54 }
55 else {
56 if (!tr[p].rc) tr[p].rc = ++num;
57 insert(tr[p].rc, mid + 1, r, val, k);
58 }
59 tr[p].dat = max(tr[tr[p].lc].dat, tr[tr[p].rc].dat);
60 tr[p].pos = tr[tr[p].lc].dat >= tr[tr[p].rc].dat ? tr[tr[p].lc].pos : tr[tr[p].rc].pos;
61 }
62
63 int merge(int p, int q, int l, int r) {//线段树合并
64 if (!p || !q) return p + q;
65 if (l == r) {
66 tr[p].dat += tr[q].dat;
67 tr[p].pos = tr[p].dat ? l : 0;
68 return p;
69 }
70 int mid = (l + r) >> 1;
71 tr[p].lc = merge(tr[p].lc, tr[q].lc, l, mid);
72 tr[p].rc = merge(tr[p].rc, tr[q].rc, mid + 1, r);
73 tr[p].dat = max(tr[tr[p].lc].dat, tr[tr[p].rc].dat);
74 tr[p].pos = tr[tr[p].lc].dat >= tr[tr[p].rc].dat ? tr[tr[p].lc].pos : tr[tr[p].rc].pos;
75 return p;
76 }
77
78 void solve(int x) {
79 for (int i = head[x]; i; i = nxt[i]) {
80 int y = to[i];
81 if (d[y] <= d[x]) continue;
82 solve(y);
83 rt[x] = merge(rt[x], rt[y], 1, cnt);
84 }
85 ans[x] = tr[rt[x]].pos;
86 }
87
88 int main() {
89 n = read(); m = read();
90 t = log2(n) + 1;
91 for (int i = 1; i < n; i++) {
92 int x = read(), y = read();
93 add(x, y), add(y, x);
94 }
95 d[1] = 1, dfs(1,0);
96 for (int i = 1; i <= n; i++) rt[i] = ++num;
97 for (int i = 1; i <= m; i++) {
98 X[i] = read(); Y[i] = read(); Z[i] = read();
99 val[i] = Z[i];
100 }
101 sort(val + 1, val + m + 1);//离散化
102 cnt = unique(val + 1, val + m + 1) - val - 1;
103 for (int i = 1; i <= m; i++) {
104 int x = X[i], y = Y[i];
105 int z = lower_bound(val + 1, val + cnt + 1, Z[i]) - val;
106 int p = lca(x, y);
107 //树上差分
108 insert(rt[x], 1, cnt, z, 1);
109 insert(rt[y], 1, cnt, z, 1);
110 insert(rt[p], 1, cnt, z, -1);
111 if (st[p][0]) insert(rt[st[p][0]], 1, cnt, z, -1);
112 }
113 solve(1);
114 for (int i = 1; i <= n; i++) printf("%d\n", val[ans[i]]);
115 return 0;
116 }
P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)的更多相关文章
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
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有约会]雨天的尾巴
[题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
- P4556 [Vani有约会]雨天的尾巴
目录 思路 优化 过程中的问题/疑问 错误 代码 思路 每个节点维护一课线段树(当然是动态开点) 线段树的作用是统计这个节点有多少种粮食型号,以及最多的粮食型号 然后树上差分,u和v点 +1,lca( ...
- 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)
传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...
- 洛咕 P4556 [Vani有约会]雨天的尾巴
终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并)
传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...
随机推荐
- [b01lers2020]Welcome to Earth-1
1.打开之后界面如下,查看源代码信息,发现chase文件,结果如下: 2.访问chase文件会一直跳转到die界面,那就只能抓包进行查看,发现leftt文件,结果如下: 3.访问leftt文件并查看源 ...
- 从零开始Blazor Server(7)--使用Furion权限验证
序 上面两篇我们讲了怎么用OnNavigateAsync来验证权限,又写了怎么用策略来验证权限. 其实我们既然集成了Fution,就可以用Furion带的方式来验证. 创建AdminHandler 我 ...
- Regular采样类定义和测试
这个算法是均匀采样算法,继承于Sampler类. 类声明: #pragma once #ifndef __REGULAR_HEADER__ #define __REGULAR_HEADER__ #in ...
- 《吐血整理》进阶系列教程-拿捏Fiddler抓包教程(11)-Fiddler设置安卓手机抓包,不会可是万万不行的!
1.简介 Fiddler不但能截获各种浏览器发出的 HTTP 请求,也可以截获各种智能手机发出的HTTP/ HTTPS 请求. Fiddler能截获 Android 和 Windows Phone 等 ...
- 【沥血整理】灰度(二值)图像重构算法及其应用(morphological reconstruction)。
不记得是怎么接触并最终研究这个课题的了,认识我的人都知道我是没有固定的研究对象的,一切看运气和当时的兴趣.本来研究完了就放在那里了,一直比较懒的去做总结,但是想一想似乎在网络上就没有看到关于这个方面的 ...
- Linux 10 安装JDK
参考源 https://www.bilibili.com/video/BV187411y7hF?spm_id_from=333.999.0.0 版本 本文章基于 CentOS 7.6 这里使用 rpm ...
- centos7.6内核之cfs_bandwidth下的distribute_cfs_runtime hard lockup
接到业务兄弟报障,出现多例crash,堆栈大多数如下: KERNEL: /usr/lib/debug/lib/modules/3.10.0-957.27.2.el7.x86_64/vmlinuxDUM ...
- Dapr中国社区活动之 分布式运行时开发者日 (2022.09.03)
自2019年10月首次发布以来,Dapr(Distributed Application Runtime,分布式应用运行时)因其"更稳定"."更可靠".&quo ...
- 面试~jvm(JVM内存结构、类加载、双亲委派机制、对象分配,了解垃圾回收)
一.JVM内存结构 ▷ 谈及内存结构各个部分的数据交互过程:还可以再谈及生命周期.数据共享:是否GC.是否OOM 答:jvm 内存结构包括程序计数器.虚拟机栈.本地方法栈.堆.方法区:它是字节码运行时 ...
- 总在用户态调试 C# 程序,终还是搭了一个内核态环境
一:背景 一直在用 WinDbg 调试用户态程序,并没有用它调试过 内核态,毕竟不是做驱动开发,也没有在分析 dump 中需要接触用内核态的需求,但未知的事情总觉得很酷,加上最近在看 <深入解析 ...