洛谷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 ...
随机推荐
- k8s之发布管理架构图01
k8s发布管理所用到的组件
- 自定义Ribbon的负载均衡策略
自定义负载均衡策略 官方文档指出:自定义的负载均衡配置类不能放在 @componentScan 所扫描的当前包下及其子包下,否则我们自定义的这个配置类就会被所有的Ribbon客户端所共享,也就是说我们 ...
- 【Python开发】anaconda3 安装python包
环境说明 电脑配置:win7 64位 安装版本:anaconda3 Python 3.6 参考链接 http://python.jobbole.com/86236/ (链接中有一个小点介绍了如何加速包 ...
- 《Linux就该这么学》培训笔记_ch23_使用OpenLDAP部署目录服务
<Linux就该这么学>培训笔记_ch23_使用OpenLDAP部署目录服务 文章主要内容: 了解目录服务 目录服务实验 配置LDAP服务端 配置LDAP客户端 了解目录服务 其实目录可以 ...
- 第一周第二部分 coursera.org
即使J(,)=,也不能是完美估计,因为其他数据可能存在误差 取任何颜色并沿着“圆”走,就可以得到相同的成本函数值,右图三个点的J(,)相同 越靠近圆心,J(,)越小 梯度下降算法可以将代价函数J()最 ...
- 最近C#项目中不小心踩的低级坑
都是很基础的错误问题,大部分都是因为不查一下资料就直接根据其它类似语言的经验写代码导致的 1. 一个企业微信上的正常的界面突然不能滚动了 本以为是浏览器代码计算问题,结果发现是JS出错导致. 2. R ...
- tomcat宕机自动重启脚本
#!/bin/bash# 获取tomcat进程ID /usr/share/tomcatTomcatID=$(ps -ef |grep tomcat |grep -w 'tomcat'|grep -v ...
- MQTT --- 操作行为
会话状态 为实现QoS等级1和QoS等级2协议流,客户端和服务端需要将状态与客户标识符相关联,这被称为会 话状态.服务端还将订阅信息存储为会话状态的一部分.会话可以跨越一系列的网络连接.它持续到最新的 ...
- 【1】【经典回溯、动态规划、贪心】【leetcode-55】跳跃游戏
给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4]输出: true解释 ...
- Redis和数据库一致性
1.实时同步 对强一致要求比较高的,应采用实时同步方案,即查询缓存查询不到再从DB查询,保存到缓存: 更新缓存时,先更新数据库,再将缓存的设置过期(建议不要去更新缓存内容,直接设置缓存过期 ...