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类型的物品.完成所有发放后,每个点存放最多 ...
随机推荐
- uCGUI 按键窗口切换机制(更新篇)
在之前文章中,讲述了一个低内存使用量的的窗口切换机制.有人会问,低内存使用量是多低呢,我这里举个例子.我有一个项目中使用到本切换机制,128*64的单色屏,初步计算有105个窗口(后面还会增加),总内 ...
- Python 3 软件开发规范
Python 3 软件开发规范 参考链接 http://www.cnblogs.com/linhaifeng/articles/6379069.html#_label14 对每个目录,文件介绍. #= ...
- inline-block间距解决方案
当我们将元素设为inline-block时,总是会莫名其妙出现一些间距 <!DOCTYPE html> <html> <head> <meta charset ...
- web框架详解之tornado 三 url和分页
一.代码目录构建 controllers :处理业务逻辑的 account:处理账户相关的 上面目录作用和内容 controllers 包 :处理业务逻辑的 account:处理账户相关的 home ...
- LINQ 学习路程 -- 查询操作 ElementAt, ElementAtOrDefault
Element Operators (Methods) Description ElementAt 返回指定索引的元素,如果索引超过集合长度,则抛出异常 ElementAtOrDefault 返回指定 ...
- FineReport报表使用
FineReport报表是帆软公司推出的可以嵌入java的免费报表. FineReport有2部分组成,一有c/s端的报表工具制作cpt结尾的报表文件:二是 java调用报表的web程序. 这里主要说 ...
- Struts 2简介
Struts 2简介 Struts 2 编辑 同义词 Struts2一般指Struts 2 Struts2是一个基于MVC设计模式的Web应用框架,它本质上相当于一个servlet,在MVC设计模式中 ...
- 一个ClientDataset的Delta与XML相互转换
一个ClientDataset的Delta与XML相互转换的文章: 大家都知道TClientDataSet的Delta属性保存数据集的变化,但是Delta是OleVariant类型的属性,这样如果用D ...
- ajax(异步页面动态刷新)
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术. AJAX = 异步 JavaScript和 ...
- Geoserver端口冲突解决方案
转载:https://blog.csdn.net/wiinder/article/details/53260642 今天在安装Geoserver的时候遇到了端口冲突的问题,即默认的8080端口与Tom ...