Luogu 4556 雨天的尾巴
主席树+线段树合并。
首先我们想一想如果只有一个结点的话,我们弄一个权值线段树就可以随便维护了。
那么我们可以运用差分的思想,把一个询问拆成四个操作,对于一个询问$(x, y, v)$,我们在$x$的$k$处$ + 1$,在$y$的$k$处$ + 1$,在$lca(x, y)$处$ - 1$,在$fa(lca(x, y))$处$ - 1$,那么每一个点最后的权值线段树的样子就相当于把它和它的子树中的权值线段树全部合并之后得到的线段树。
动态开点就可以了。
前置技能:线段树合并。 戳这里
这样子我们往下搜一遍把每一个点和它的儿子合并,然后记录一下答案就可以了。
不会算时间复杂度QωQ。
另外,这题数据很卡,我写了内存回收 + $queue$开了$O2$才卡过。
Code:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std; const int N = 1e5 + ;
const int Lg = ; int n, m, maxn = , tot = , head[N], ans[N];
int fa[N][Lg], dep[N], inx[N], iny[N], inv[N], val[N]; struct Edge {
int to, nxt;
} e[N << ]; inline void add(int from, int to) {
e[++tot].to = to;
e[tot].nxt = head[from];
head[from] = tot;
} struct Innum {
int val, id;
} in[N]; bool cmp(const Innum &x, const Innum &y) {
if(x.val != y.val) return x.val < y.val;
else return x.id < y.id;
} inline void swap(int &x, int &y) {
int t = x; x = y; y = t;
} inline void chkMax(int &x, int y) {
if(y > x) x = y;
} inline int min(int x, int y) {
return x > y ? y : x;
} inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline void discrete() {
sort(in + , in + + m, cmp);
for(int cnt = , i = ; i <= m; i++) {
if(in[i].val != in[i - ].val) ++cnt;
chkMax(maxn, cnt);
inv[in[i].id] = cnt;
val[cnt] = in[i].val;
}
} void dfs(int x, int fat, int depth) {
dep[x] = depth, fa[x][] = fat;
for(int i = ; i <= ; i++)
fa[x][i] = fa[fa[x][i - ]][i - ];
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fat) continue;
dfs(y, x, depth + );
}
} inline int getLca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(int i = ; i >= ; i--)
if(dep[fa[x][i]] >= dep[y])
x = fa[x][i];
if(x == y) return x;
for(int i = ; i >= ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][];
} namespace PSegT {
struct Node {
int lc, rc, sum, col;
} s[N * ]; int root[N], nodeCnt = ; queue <int> Q; inline void push(int x) {
Q.push(x);
} inline int newNode() {
if(Q.empty()) return ++nodeCnt;
else {
int res = Q.front();
Q.pop();
return res;
}
} #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define sum(p) s[p].sum
#define col(p) s[p].col
#define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
if(sum(lc(p)) < sum(rc(p))) col(p) = col(rc(p)), sum(p) = sum(rc(p));
else col(p) = col(lc(p)), sum(p) = sum(lc(p));
} void modify(int &p, int l, int r, int x, int v) {
if(!p) p = newNode();
if(l == r) {
sum(p) += v;
if(sum(p) > ) col(p) = l;
else col(p) = ;
return;
} if(x <= mid) modify(lc(p), l, mid, x, v);
else modify(rc(p), mid + , r, x, v);
up(p);
} int merge(int u, int v, int l, int r) {
if(!u || !v) return u + v;
int p = newNode();
if(l == r) {
sum(p) = sum(u) + sum(v);
if(sum(p) > ) col(p) = l;
else col(p) = ;
} else {
lc(p) = merge(lc(u), lc(v), l, mid);
rc(p) = merge(rc(u), rc(v), mid + , r);
up(p);
}
push(u), push(v);
return p;
} } using namespace PSegT; void solve(int x) {
for(int i = head[x]; i; i = e[i].nxt) {
int y = e[i].to;
if(y == fa[x][]) continue;
solve(y);
root[x] = merge(root[x], root[y], , maxn);
} /* printf("%d: ", x);
for(int i = 1; i <= maxn; i++)
printf("%d ", query(root[id[x] - 1], root[id[x]], 1, maxn, i));
printf("\n"); */ ans[x] = val[s[root[x]].col];
} int main() {
read(n), read(m);
for(int x, y, i = ; i < n; i++) {
read(x), read(y);
add(x, y), add(y, x);
}
dfs(, , ); // maxn = 1e5; for(int i = ; i <= m; i++) {
read(inx[i]), read(iny[i]), read(inv[i]);
in[i].id = i, in[i].val = inv[i];
}
discrete(); for(int x, y, v, z, w, i = ; i <= m; i++) {
x = inx[i], y = iny[i], v = inv[i];
z = getLca(x, y), w = fa[z][]; /* vec[x].push_back(pin(v, 1));
vec[y].push_back(pin(v, 1));
vec[z].push_back(pin(v, -1));
if(w) vec[w].push_back(pin(v, -1)); */ modify(root[x], , maxn, v, );
modify(root[y], , maxn, v, );
modify(root[z], , maxn, v, -);
if(w) modify(root[w], , maxn, v, -);
} /* printf("\n");
for(int i = 1; i <= n; i++) {
printf("%d: ", i);
for(int j = 1; j <= maxn; j++)
printf("%d ", query(root[id[i] - 1], root[id[i] + siz[i] - 1], 1, maxn, j));
printf("\n");
}
printf("\n"); */ solve(); for(int i = ; i <= n; i++)
printf("%d\n", ans[i]); return ;
}
Luogu 4556 雨天的尾巴的更多相关文章
- Luogu 4556 雨天的尾巴 - 启发式合并线段树
Solution 用$col$记录 数量最多的种类, $sum$记录 种类$col$ 的数量. 然后问题就是树上链修改, 求 每个节点 数量最多的种类. 用树上差分 + 线段树合并更新即可. Code ...
- [luogu4556]雨天的尾巴
[luogu4556]雨天的尾巴 luogu 发现是一顿子修改然后再询问,那么把修改树上差分一下再线段树合并 但是... 如果你只有35分... https://www.luogu.org/discu ...
- P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)
P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...
- BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )
路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, ...
- BZOJ_3307_雨天的尾巴_线段树合并+树上差分
BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...
- [Vani有约会]雨天的尾巴 线段树合并
[Vani有约会]雨天的尾巴 LG传送门 线段树合并入门好题. 先别急着上线段树合并,考虑一下这题的暴力.一看就是树上差分,对于每一个节点统计每种救济粮的数量,再一遍dfs把差分的结果统计成答案.如果 ...
- 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)
3307: 雨天的尾巴 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 458 Solved: 210 Description N个点,形成一个树状结 ...
- 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告
P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...
- 【BZOJ3307】雨天的尾巴 线段树合并
[BZOJ3307]雨天的尾巴 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多 ...
随机推荐
- Android系统OTA升级包制作【转】
本文转载自:http://blog.csdn.net/dingfengnupt88/article/details/52882788 Android系统升级分为整包升级和差分包升级,整包升级就是将系统 ...
- EntityFramework 学习 一 Persistence in Entity Framework
实体框架的持久化 当用EntityFramework持久化一个对象时,有两种情形:连接的和断开的 1.连接场景:使用同一个context上下文从数据库中查询和持久化实体时,查询和持久化实体期间,con ...
- EntityFramework 学习 一 Model Browser
我们已经为School表创建第一个实体数据模型,可视化的EDM设计器不显示所有的实体,而是显示和数据库中对应的表和视图 Model Browser为你提供关于所有对象和函数的信息, Diagrams ...
- 投影矩阵、最小二乘法和SVD分解
投影矩阵广泛地应用在数学相关学科的各种证明中,但是由于其概念比较抽象,所以比较难理解.这篇文章主要从最小二乘法的推导导出投影矩阵,并且应用SVD分解,写出常用的几种投影矩阵的形式. 问题的提出 已知有 ...
- 2015年SCI收录遥感期刊28种目录
链接地址:http://blog.sciencenet.cn/blog-57081-928025.html
- PHP继承中$this的问题
在父类中的构造函数中使用$this , 这是$this指的是正在实例化的子类对象,不管是parent还是继承调用父类的构造函数. 如: class CompanyController extends ...
- JQUERY Uploadify 3.1 C#使用案例
近来因为要做一个上传功能,而firefox又不能直接使用file这样的标签,所以试着用js来写了一个,结果发现代码太多,验证太复杂,而且效果也不理想. 相对的,jquery提供的这一套uploadif ...
- PHP获取指定日期是星期几的实现方法
这篇文章主要介绍了PHP获取指定日期是星期几的实现方法,涉及php针对日期的读取.判断与字符串.数组相关运算操作技巧,需要的朋友可以参考下 本文实例讲述了PHP获取指定日期是星期几的实现方法.分享给大 ...
- input 限制输入
只能输入数字 :<input type="text" onkeyup="value=value.replace(/[^\d]/g,'')" /> 只 ...
- 关键字volidate和transient(转)
Volatile修饰的成员变量在每次被线程访问时,都强迫从主内存中重读该成员变量的值.而且,当成员变量发生变化时,强迫线程将变化值回写到主内存.这样在任何时刻,两个不同的线程总是看到某个成员变量的同一 ...