洛谷P4556 雨天的尾巴(线段树合并)
洛谷P4556 雨天的尾巴
题解:
因为一个点可能存放多种物品,直接开二维数组进行统计时间、空间复杂度都不能承受。因为每一个点所拥有的物品只与其子树中的点有关,所以可以考虑对每一个点来建立一颗权值线段树来维护多种物品以及其数量,然后最后在回溯时合并,这样就可以得到我们所需要的信息了。
因为题目中要求的是哪一种物品,所以我们可以顺带维护一下位置信息,就不用到时候每次去query了。
注意一下,就是当一个点的sum为0时,其pos应该为置为0。
详见代码吧:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n, m;
struct Edge{
int v, next;
}e[N << 1];
int head[N], tot, D;
void adde(int u, int v) {
e[tot].v = v; e[tot].next = head[u]; head[u] = tot++;
}
int f[N][22], deep[N] ;
int rt[N], ls[N * 100], rs[N * 100], pos[N * 100], sum[N * 100] ;
int X[N], Y[N], Z[N], b[N], ans[N];
void dfs1(int u, int fa) {
deep[u] = deep[fa] + 1;
for(int i = head[u]; i != -1; i = e[i].next){
int v = e[i].v;
if(v == fa) continue ;
f[v][0] = u;
for(int j = 1; j <= 20; j++) f[v][j] = f[f[v][j - 1]][j - 1] ;
dfs1(v, u) ;
}
}
int LCA(int x, int y) {
if(deep[x] < deep[y]) swap(x, y);
for(int i = 20; i >= 0; i--) {
if(deep[f[x][i]] >= deep[y]) x = f[x][i] ;
}
if(x == y) return x;
for(int i = 20; i >= 0; i--) {
if(f[x][i] != f[y][i]) x = f[x][i], y = f[y][i] ;
}
return f[x][0] ;
}
void insert(int o, int l, int r, int val, int sign) {
if(l == r) {
sum[o] += sign;
pos[o] = sum[o] > 0 ? l : 0;
return ;
}
int mid = (l + r) >> 1;
if(val <= mid) {
if(!ls[o]) ls[o] = ++tot;
insert(ls[o], l, mid, val, sign) ;
} else {
if(!rs[o]) rs[o] = ++tot;
insert(rs[o], mid + 1, r, val, sign) ;
}
sum[o] = max(sum[ls[o]], sum[rs[o]]) ;
pos[o] = sum[ls[o]] >= sum[rs[o]] ? pos[ls[o]] : pos[rs[o]];
}
int merge(int x, int y, int l, int r) {
if(!x) return y;
if(!y) return x;
if(l == r) {
sum[x] += sum[y] ;
pos[x] = sum[x] > 0 ? l : 0;
return x;
}
int mid = (l + r) >> 1;
ls[x] = merge(ls[x], ls[y], l, mid) ;
rs[x] = merge(rs[x], rs[y], mid + 1, r) ;
sum[x] = max(sum[ls[x]], sum[rs[x]]) ;
pos[x] = sum[ls[x]] >= sum[rs[x]] ? pos[ls[x]] : pos[rs[x]] ;
return x;
}
void dfs2(int u, int fa) {
for(int i = head[u]; i != -1; i = e[i].next) {
int v = e[i].v;
if(v == fa) continue ;
dfs2(v, u) ;
rt[u] = merge(rt[u], rt[v], 1, D) ;
}
ans[u] = pos[rt[u]];
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m;
memset(head, -1, sizeof(head)) ;
for(int i = 1; i < n; i++) {
int u, v;
cin >> u >> v;
adde(u, v); adde(v, u);
}
dfs1(1, 0) ;
for(int i = 1; i <= n; i++) rt[i] = i;
tot = n;
for(int i = 1; i <= m; i++) {
cin >> X[i] >> Y[i] >> Z[i] ;
b[i] = Z[i] ;
}
sort(b + 1, b + m + 1);
D = unique(b + 1, b + m + 1) - b - 1;
for(int i = 1; i <= m; i++) {
int x = X[i], y = Y[i], z = Z[i] ;
int k = lower_bound(b + 1, b + D + 1, z) - b;
int lca = LCA(x, y) ;
insert(rt[x], 1, D, k, 1) ;
insert(rt[y], 1, D, k, 1) ;
insert(rt[lca], 1, D, k, -1) ;
if(f[lca][0]) insert(rt[f[lca][0]], 1, D, k, -1) ;
}
dfs2(1, 0) ;
for(int i = 1; i <= n; i++) cout << b[ans[i]] << '\n' ;
return 0;
}
洛谷P4556 雨天的尾巴(线段树合并)的更多相关文章
- 洛谷P4556 雨天的尾巴 线段树
正解:线段树合并 解题报告: 传送门! 考虑对树上的每个节点开一棵权值线段树,动态开点,记录一个max(num,id)(这儿的id,define了一下,,,指的是从小到大排QAQ 然后修改操作可以考虑 ...
- P4556 雨天的尾巴 线段树合并
使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...
- [洛谷P4556] 雨天的尾巴
这道题可以用线段树合并做,网上的题解基本上都是线段树合并的. 但是为什么我就偏偏要用dsu on tree...... 题目传送门 dsu on tree的方法类似[CF1009F] Dominant ...
- [洛谷 P4556] 雨天的尾巴
传送门 Solution 线段树合并的入门题 lca可以在dfs的时候离线求(用并查集) 更新的点有每条链的两个端点,它们的lca和dad[lca] 为了节省空间,lca和dad[lca]的更新可以先 ...
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- 【BZOJ3307】雨天的尾巴 线段树合并
[BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...
- 洛谷P3899 [湖南集训]谈笑风生(线段树合并)
题意 题目链接 Sol 线段树合并板子题,目前我看到两种写法,分别是这样的. 前一种每次需要新建一个节点,空间是\(O(4nlogn)\) 后者不需要新建,空间是\(O(nlogn)\)(面向数据算空 ...
- BZOJ3307雨天的尾巴——线段树合并
题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来N ...
- 洛谷P3521 [POI2011]ROT-Tree Rotation [线段树合并]
题目传送门 Tree Rotation 题目描述 Byteasar the gardener is growing a rare tree called Rotatus Informatikus. I ...
随机推荐
- 【Kubernetes学习之一】Kubernetes 简介
环境 centos 7 一.概念和组件Kubernetes是Google开源的一个容器编排引擎,它支持自动化部署.大规模可伸缩.应用容器化管理,简称k8s. 1.Master Kubernetes中的 ...
- 使用vue搭建应用六实现登录页
1.js_cookie js-cookie插件是一个JS操作cookie的插件 安装 yarn add js-cookie 使用 写入 Cookies.set('name', 'value'); 读取 ...
- 怎样把excel整列单元格批量改为文本格式
选中整列,进入“数据”菜单栏,点击“分列”,[列数据格式]选“文本”,点击“完成”即可.
- Python【每日一问】29
问: [基础题]:给一个不多于 5 位的正整数,要求:一.求它是几位数,二.逆序印出各位数字[提高题]:某个公司采用公用电话传递数据,数据是四位的整数,在传递过程中是加密的,加密规则如下:每位数字都加 ...
- NOI-动规题目集锦
162:Post Office 解题思路 #include<bits/stdc++.h> using namespace std; ],f[][],mi[][],i,j; int main ...
- [EXP]CVE-2019-1821 Cisco Prime Infrastructure思科未授权远程代码执行漏洞
CVE-2019-1821 Cisco Prime Infrastructure Remote Code Execution https://srcincite.io/blog/2019/05/17/ ...
- javascript的立即执行函数
在javascript中有引入立即执行函数的概念,那么什么是立即执行函数呢?立即执行函数又是怎么写的呢?立即执行函数与普通函数有什么区别呢? 先来看看一般的函数: function a(){ var ...
- Flink 源码解析 —— 如何获取 StreamGraph?
StreamGraph https://t.zsxq.com/qRFIm6I 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭 ...
- (火狐浏览器)前端以FormData类形成表单(含文件),通过ajax提交,PHP后端iconv()报“文件名含有非法字符”且POST中的‘Ttitle’丢失
[错误信息]后端获取的POST中丢失了Ttile,文件名乱码导致iconv()出错,利用mb_detect_encoding()函数检测输入的字符串,返回false; mb_detect_encodi ...
- 什么是 Shell?
简单来说“Shell编程就是对一堆Linux命令的逻辑化处理”. Shell 编程的 Hello World 学习任何一门编程语言第一件事就是输出HelloWord了!下面我会从新建文件到shell代 ...