主席树+线段树合并。

首先我们想一想如果只有一个结点的话,我们弄一个权值线段树就可以随便维护了。

那么我们可以运用差分的思想,把一个询问拆成四个操作,对于一个询问$(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 雨天的尾巴的更多相关文章

  1. Luogu 4556 雨天的尾巴 - 启发式合并线段树

    Solution 用$col$记录 数量最多的种类, $sum$记录 种类$col$ 的数量. 然后问题就是树上链修改, 求 每个节点 数量最多的种类. 用树上差分 + 线段树合并更新即可. Code ...

  2. [luogu4556]雨天的尾巴

    [luogu4556]雨天的尾巴 luogu 发现是一顿子修改然后再询问,那么把修改树上差分一下再线段树合并 但是... 如果你只有35分... https://www.luogu.org/discu ...

  3. P4556 [Vani有约会]雨天的尾巴(线段树合并+lca)

    P4556 [Vani有约会]雨天的尾巴 每个操作拆成4个进行树上差分,动态开点线段树维护每个点的操作. 离线处理完向上合并就好了 luogu倍增lca被卡了5分.....于是用rmq维护.... 常 ...

  4. 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). 复杂度看起来不高, ...

  5. BZOJ_3307_雨天的尾巴_线段树合并+树上差分

    BZOJ_3307_雨天的尾巴_线段树合并 Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y 对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成 所有发放后 ...

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

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

  7. 【BZOJ 3307】 3307: 雨天的尾巴 (线段树+树链剖分)

    3307: 雨天的尾巴 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 458  Solved: 210 Description N个点,形成一个树状结 ...

  8. 洛谷 P4556 [Vani有约会]雨天的尾巴 解题报告

    P4556 [Vani有约会]雨天的尾巴 题目背景 深绘里一直很讨厌雨天. 灼热的天气穿透了前半个夏天,后来一场大雨和随之而来的洪水,浇灭了一切. 虽然深绘里家乡的小村落对洪水有着顽固的抵抗力,但也倒 ...

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

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

随机推荐

  1. Python 3 udp 套接字

    Python 3 udp套接字 TCP是建立可靠连接,并且通信双方都可以以流的形式发送数据.相对TCP,UDP则是面向无连接的协议 使用UDP协议时,不需要建立连接,只需要知道对方的IP地址和端口号, ...

  2. POJ 2536 之 Gopher II(二分图最大匹配)

    Gopher II Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 6675   Accepted: 2732 Descrip ...

  3. 大话设计模式--桥接模式 Bridge -- C++实现实例

    1. 桥接模式: 将抽象部分与它的实现部分分离,使它们都可以独立的变化. 分离是指 抽象类和它的派生类用来实现自己的对象分离. 实现系统可以有多角度分类,每一种分类都有可能变化,那么把这种多角度分离出 ...

  4. Codeforces Round #335 (Div. 2) C. Sorting Railway Cars

    C. Sorting Railway Cars time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  5. Keep DNS Nameserver Order Consistency In Neutron

    一个subnet有多个dns server时,dns server在创建时就定好了,但可以update: neutron subnet-update 1a2d261b-b233-3ab9-902e-8 ...

  6. 七 Django框架,models.py模块,数据库操作——F和Q()运算符:|或者、&并且——queryset对象序列化

    F()可以将数据库里的数字类型的数据,转换为可以数字类型 首先要导入 from django.db.models import F from django.shortcuts import rende ...

  7. Git_学习_01_ 常用 Git 命令清单

    我每天使用 Git ,但是很多命令记不住. 一般来说,日常使用只要记住下图6个命令,就可以了.但是熟练使用,恐怕要记住60-100个命令. 下面是我整理的常用 Git 命令清单.几个专用名词的译名如下 ...

  8. 2018.5.28 PSOC第一枪:基于cypress的蓝牙开发

    Cypress-BLE 开发套件可以快速开发 物联网电子产品. PSOC编程特点: A 拖放各PSoC 组件到工作区中,以设计原理图B 完成各组件之间的布线,并配置GPIOC 使用所包含的组件API ...

  9. stl_iterator.h

    stl_iterator.h // Filename: stl_iterator.h // Comment By: 凝霜 // E-mail: mdl2009@vip.qq.com // Blog: ...

  10. FFmpeg 'scale' filter not present, cannot convert pixel formats.

    /*************************************************************************** * FFmpeg 'scale' filter ...