洛谷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 雨天的尾巴(线段树合并)的更多相关文章

  1. 洛谷P4556 雨天的尾巴 线段树

    正解:线段树合并 解题报告: 传送门! 考虑对树上的每个节点开一棵权值线段树,动态开点,记录一个max(num,id)(这儿的id,define了一下,,,指的是从小到大排QAQ 然后修改操作可以考虑 ...

  2. P4556 雨天的尾巴 线段树合并

    使用线段树合并,每个节点维护一棵权值线段树,下标为救济粮种类,区间维护数量最多的救济粮编号(下标).所以每个节点答案即为\(tre[rot[x]]\). 然后运用树上点的差分思想,对于分发路径\(u, ...

  3. [洛谷P4556] 雨天的尾巴

    这道题可以用线段树合并做,网上的题解基本上都是线段树合并的. 但是为什么我就偏偏要用dsu on tree...... 题目传送门 dsu on tree的方法类似[CF1009F] Dominant ...

  4. [洛谷 P4556] 雨天的尾巴

    传送门 Solution 线段树合并的入门题 lca可以在dfs的时候离线求(用并查集) 更新的点有每条链的两个端点,它们的lca和dad[lca] 为了节省空间,lca和dad[lca]的更新可以先 ...

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

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

  6. 【BZOJ3307】雨天的尾巴 线段树合并

    [BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...

  7. 洛谷P3899 [湖南集训]谈笑风生(线段树合并)

    题意 题目链接 Sol 线段树合并板子题,目前我看到两种写法,分别是这样的. 前一种每次需要新建一个节点,空间是\(O(4nlogn)\) 后者不需要新建,空间是\(O(nlogn)\)(面向数据算空 ...

  8. BZOJ3307雨天的尾巴——线段树合并

    题目描述 N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. 输入 第一行数字N,M接下来N ...

  9. 洛谷P3521 [POI2011]ROT-Tree Rotation [线段树合并]

    题目传送门 Tree Rotation 题目描述 Byteasar the gardener is growing a rare tree called Rotatus Informatikus. I ...

随机推荐

  1. 全球 IPv4 地址正式耗尽

    重要消息: 就在 2019/11/25 UTC+1 15:35 时,一封来自欧洲 RIPE NCC 的邮件中得到确认:全球的IPv4地址已经彻底耗尽. IPv4 大家应该很熟悉了,就是我们平常所知道的 ...

  2. 应用JWT进行用户认证及Token的刷新

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  3. laravel代码规范强制检查

    目录 介绍 代码规范检查与修复 在git commit时自动检查代码规范 后记 介绍 在团队协作开发中,代码规范是必要的.以前的规范都是自己定,然后手动检查,很难做到有效的约束. 现代的PHP,则有得 ...

  4. 【计算机视觉】BRIEF特征匹配

    Binary Robust Independent Elementary Features www.cnblogs.com/ronny 1. BRIEF的基本原理 我们已经知道SIFT特征采用了128 ...

  5. rpm续

    一.安装源码包 安装源码包通常须要一下三步: (1) ./configure. 这步可以定制功能,加上相应 的选项即可,具体有什么选项可以通过命令./configure help来查看.这一步会 自动 ...

  6. Python3+PyCryptodome实现各种加密算法教程

    一.说明 PyCryptodome是python一个强大的加密算法库,可以实现常见的单向加密.对称加密.非对称加密和流加密算法.直接pip安装即可: pip install pycryptodome ...

  7. [转帖]Linux操作系统定时任务系统 Cron 入门0

    Linux操作系统定时任务系统 Cron 入门 https://www.cnblogs.com/zhuiluoyu/p/5646400.html   cron是一个linux下的定时执行工具,可以在无 ...

  8. 概述UML——UML系列篇一

    前言 作为Java应用开发者,日益感觉到对象建模的重要性.系统的复杂性,对于不能全局掌握的我和编程时没有对象模型指导时,编写实现代码时,感觉甚是困难.处于这些原因,这里想借助学习UML建模,在分析需求 ...

  9. 另一个角度的redis--redis 可以看做是c/s架构的软件

    Redis 通信协议简单研究 redis 可以看做是c/s架构的软件,再打开一个终端输入下面的指令 https://www.cnblogs.com/nele/p/8908298.html redis ...

  10. Introducing KSQL: Streaming SQL for Apache Kafka

    Update: KSQL is now available as a component of the Confluent Platform. I’m really excited to announ ...