P4556 [Vani有约会]雨天的尾巴 (线段树合并)
P4556 [Vani有约会]雨天的尾巴
题意:
首先村落里的一共有n座房屋,并形成一个树状结构。然后救济粮分m次发放,每次选择两个房屋(x,y),然后对于x到y的路径上(含x和y)每座房子里发放一袋z类型的救济粮。
然后深绘里想知道,当所有的救济粮发放完毕后,每座房子里存放的最多的是哪种救济粮。
题解:
树链剖分的写法很明显了,维护一个max即可
讲一下线段树合并的写法
区间更新用单点更新和差分来代替,求一个LCA,x->y的更新即可用在点x+1,点y+1,点lca(x,y)-1,点fa(lca(x,y))-1 后,线段树合并来取代, 线段树维护最多的救济粮编号val,最多救济粮的数量sum,然后在合并的时候就可以统计出u节点的答案了
代码
/**
* ┏┓ ┏┓
* ┏┛┗━━━━━━━┛┗━━━┓
* ┃ ┃
* ┃ ━ ┃
* ┃ > < ┃
* ┃ ┃
* ┃... ⌒ ... ┃
* ┃ ┃
* ┗━┓ ┏━┛
* ┃ ┃ Code is far away from bug with the animal protecting
* ┃ ┃ 神兽保佑,代码无bug
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┃
* ┃ ┗━━━┓
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛
*/
// warm heart, wagging tail,and a smile just for you!
//
// _ooOoo_
// o8888888o
// 88" . "88
// (| -_- |)
// O\ = /O
// ____/`---'\____
// .' \| |// `.
// / \||| : |||// \
// / _||||| -:- |||||- \
// | | \ - /// | |
// | \_| ''\---/'' | |
// \ .-\__ `-` ___/-. /
// ___`. .' /--.--\ `. . __
// ."" '< `.___\_<|>_/___.' >'"".
// | | : `- \`.;`\ _ /`;.`/ - ` : | |
// \ \ `-. \_ __\ /__ _/ .-` / /
// ======`-.____`-.___\_____/___.-`____.-'======
// `=---='
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// 佛祖保佑 永无BUG
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int, int> pii;
typedef unsigned long long uLL;
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define bug printf("*********\n")
#define FIN freopen("input.txt","r",stdin);
#define FON freopen("output.txt","w+",stdout);
#define IO ios::sync_with_stdio(false),cin.tie(0)
#define debug1(x) cout<<"["<<#x<<" "<<(x)<<"]\n"
#define debug2(x,y) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<"]\n"
#define debug3(x,y,z) cout<<"["<<#x<<" "<<(x)<<" "<<#y<<" "<<(y)<<" "<<#z<<" "<<z<<"]\n"
const int maxn = 3e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double Pi = acos(-1);
LL gcd(LL a, LL b) {
return b ? gcd(b, a % b) : a;
}
LL lcm(LL a, LL b) {
return a / gcd(a, b) * b;
}
double dpow(double a, LL b) {
double ans = 1.0;
while(b) {
if(b % 2)ans = ans * a;
a = a * a;
b /= 2;
} return ans;
}
LL quick_pow(LL x, LL y) {
LL ans = 1;
while(y) {
if(y & 1) {
ans = ans * x % mod;
} x = x * x % mod;
y >>= 1;
} return ans;
}
struct EDGE {
int v, nxt;
} edge[maxn << 1];
int head[maxn], tot;
void add_edge(int u, int v) {
edge[tot].v = v;
edge[tot].nxt = head[u];
head[u] = tot++;
}
struct node {
int l, r, sum, val;
} tree[maxn * 40];
int root[maxn];
int tree_cnt;
int sz[maxn], dep[maxn], fa[maxn], top[maxn], w[maxn], son[maxn], W[maxn], cnt;
void init() {
dep[1] = 1; fa[1] = 0;
memset(head, -1, sizeof(head));
tree_cnt = 0;
tot = 0;
cnt = 0;
}
#define ls tree[rt].l
#define rs tree[rt].r
void push_up(int rt) {
if(tree[ls].sum > tree[rs].sum) {
tree[rt].sum = tree[ls].sum;
tree[rt].val = tree[ls].val;
} else if(tree[ls].sum == tree[rs].sum) {
tree[rt].sum = tree[ls].sum;
tree[rt].val = min(tree[ls].val, tree[rs].val);
} else {
tree[rt].sum = tree[rs].sum;
tree[rt].val = tree[rs].val;
}
}
void update(int &x, int l, int r, int pos, int val) {
if(!x) x = ++tree_cnt;
if(l == r) {
tree[x].sum += val;
if(tree[x].sum) {
tree[x].val = l;
} else {
tree[x].val = 0;
}
return;
}
int mid = (l + r) >> 1;
if(pos <= mid) update(tree[x].l, l, mid, pos, val);
else update(tree[x].r, mid + 1, r, pos, val);
push_up(x);
}
void merge(int &x, int y, int l, int r) {
if(!x || !y) {
x = x + y;
return;
}
if(l == r) {
tree[x].sum += tree[y].sum;
if(tree[x].sum) {
tree[x].val = l;
} else {
tree[x].val = 0;
}
return;
}
int mid = (l + r) >> 1;
merge(tree[x].l, tree[y].l, l, mid);
merge(tree[x].r, tree[y].r, mid + 1, r);
push_up(x);
}
void dfs1(int u) {
sz[u] = 1; son[u] = 0;
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (v != fa[u]) {
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v);
sz[u] += sz[v];
if (sz[v] > sz[son[u]]) son[u] = v;
}
}
}
void dfs2(int u, int tp, int x) {
top[u] = tp; w[u] = ++cnt; W[cnt] = u;
if (son[u]) dfs2(son[u], tp, 1);
for (int i = head[u]; ~i; i = edge[i].nxt) {
int v = edge[i].v;
if (v == son[u] || v == fa[u]) continue;
dfs2(v, v, 2);
}
}
int LCA(int x, int y) {
while (top[x] != top[y]) {
if (dep[top[x]] < dep[top[y]]) std::swap(x, y);
x = fa[top[x]];
}
if (dep[x] > dep[y]) std::swap(x, y);
return x;
}
int ans[maxn];
void dfs(int u, int fa) {
for(int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if(v == fa) continue;
dfs(v, u);
merge(root[u], root[v], 1, 100000);
}
ans[u] = tree[root[u]].val;
}
int main() {
#ifndef ONLINE_JUDGE
FIN
#endif
int n, m;
init();
scanf("%d%d", &n, &m);
for(int i = 1; i < n; i++) {
int u, v;
scanf("%d%d", &u, &v);
add_edge(u, v);
add_edge(v, u);
}
dfs1(1);
dfs2(1, 1, 1);
for(int i = 1; i <= m; i++) {
int x, y, z;
scanf("%d%d%d", &x, &y, &z);
int lca = LCA(x, y);
update(root[x], 1, 100000, z, 1);
// bug;
update(root[y], 1, 100000, z, 1);
update(root[lca], 1, 100000, z, -1);
if(fa[lca]) update(root[fa[lca]], 1, 100000, z, -1);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) {
printf("%d\n", ans[i]);
}
return 0;
}
P4556 [Vani有约会]雨天的尾巴 (线段树合并)的更多相关文章
- 洛谷P4556 [Vani有约会]雨天的尾巴(线段树合并)
题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒了几座老房子,几棵老树被连根拔起,以及田地 ...
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)
P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...
- [题解] P4556 [Vani有约会]雨天的尾巴
[题解] P4556 [Vani有约会]雨天的尾巴 ·题目大意 给定一棵树,有m次修改操作,每次修改 \(( x\) \(y\) \(z )\) 表示 \((x,y)\) 之间的路径上数值 \(z\) ...
- 2018.08.28 洛谷P4556 [Vani有约会]雨天的尾巴(树上差分+线段树合并)
传送门 要求维护每个点上出现次数最多的颜色. 对于每次修改,我们用树上差分的思想,然后线段树合并统计答案就行了. 注意颜色很大需要离散化. 代码: #include<bits/stdc++.h& ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并)
传送门 一道线段树合并 首先不难看出树上差分 我们把每一次修改拆成四个,在\(u,v\)分别放上一个,在\(lca\)和\(fa[lca]\)各减去一个,那么只要统计一下子树里的总数即可 然而问题就在 ...
- P4556 [Vani有约会]雨天的尾巴 /【模板】线段树合并 (树上差分+线段树合并)
显然的树上差分问题,最后要我们求每个点数量最多的物品,考虑对每个点建议线段树,查询子树时将线段树合并可以得到答案. 用动态开点的方式建立线段树,注意离散化. 1 #include<bits/st ...
- 洛咕 P4556 [Vani有约会]雨天的尾巴
终于把考试题清完了...又复活了... 树上差分,合并用线段树合并,但是空间会炸. 某大佬:lca和fa[lca]减得时候一定已经存在这个节点了,所以放进vector里,合并完之后减掉就好了... 玄 ...
随机推荐
- @codeforces - 1276F@ Asterisk Substrings
目录 @description@ @solution@ @accepted code@ @details@ @description@ 给定一个包含 n 个小写字母的字符串 s,用 s 生成 n 个串 ...
- Mybatis中输出映射resultType与resultMap的区别
Mybatis中输出映射resultType与resultMap的区别 (原文地址:http://blog.csdn.net/acmman/article/details/46509375) 一.re ...
- HDU-1024_Max Sum Plus Plus
Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) P ...
- Effective C++: 02构造、析构、赋值运算
05:了解C++默默编写并调用哪些函数 1:一个空类,如果你自己没声明,编译器就会为它声明(编译器版本的)一个copy构造函数.一个copy assignment操作符和一个析构函数.此外如果你没有声 ...
- HDU 5672 String【尺取法】
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5672 题意: 有一个10≤长度≤1,000,000的字符串,仅由小写字母构成.求有多少个子串,包含有 ...
- iOS编译错误#ld: warning: ignoring file# 之 Undefined symbols for architecture x86_64 - ld: symbol(s) not found for architecture x86_64
ld: warning: ignoring file xxxPath/libbaidumapapi.a, missing required architecture x86_64 in file xx ...
- 卸载ROS命令
ROS有问题需要卸载只需输入以下命令: sudo apt-get purge ros-* sudo rm -rf /etc/ros
- python 清空文件夹
#!/usr/bin/env python# -*- coding:utf-8 -*-import os def del_file(path): for i in os.listdir(path): ...
- 4.2.1 Data Flow-File Write-基本过程
- 模板—插头dp(Ural 1519 Formula 1)
括号表示法: 据说比下一个要快而且灵活. #include<iostream> #include<cstring> #include<cstdio> #define ...