首先考虑序列怎么做。。。

只要把操作差分了,记录在每个点上

然后维护一棵权值线段树,表示每个颜色出现的次数,支持单点修改和查询最大值操作

只要把序列扫一遍就好了,时间复杂度$O(n + m*logZ)$,其中$n$表述序列长度,$m$表示操作次数,$Z$表示颜色集合大小

于是树形的时候,先树链剖分,然后把操作离线,对每一条链都扫一遍就好了,时间复杂度$O(n + m*logn*logZ)$

 /**************************************************************
Problem: 3307
User: rausen
Language: C++
Result: Accepted
Time:5120 ms
Memory:86068 kb
****************************************************************/ #include <cstdio>
#include <algorithm> using namespace std;
const int N = 1e5 + ;
const int Z = 1e9 + ; inline int read(); struct seg {
seg *ls, *rs;
int mx, wmx;
int tag; seg() {} #define Len (1 << 16)
inline void* operator new(size_t) {
static seg *mempool, *c;
if (mempool == c)
mempool = (c = new seg[Len]) + Len;
return c++;
}
#undef Len
inline void operator = (const seg &s) {
mx = s.mx, wmx = s.wmx;
} inline void update() {
if (!ls && !rs) this -> mx = ;
else if (!ls || !rs) *this = (ls ? *ls : *rs);
else if (ls -> mx >= rs -> mx) *this = *ls;
else *this = *rs;
}
inline void clear() {
tag = , mx = ;
}
inline void push() {
if (tag) {
if (ls) ls -> clear();
if (rs) rs -> clear();
tag = ;
}
} #define mid (l + r >> 1)
void modify(int l, int r, int pos, int d) {
if (l == r) {
mx += d, wmx = l;
return;
}
push();
if (pos <= mid) {
if (!ls) ls = new()seg;
ls -> modify(l, mid, pos, d);
} else {
if (!rs) rs = new()seg;
rs -> modify(mid + , r, pos, d);
}
update();
}
#undef mid
} *T; struct edge {
int next, to;
edge(int _n = , int _t = ) : next(_n), to(_t) {}
} e[N << ];
int first[N], tot; struct oper {
int next, z, d;
oper(int _n = , int _z = , int _d = ) : next(_n), z(_z), d(_d) {}
} op[N << ];
int First[N], tot_op; struct tree_node {
int fa, son, top;
int sz, dep;
} tr[N]; int n, m;
int ans[N]; inline void Add_Edges(int x, int y) {
e[++tot] = edge(first[x], y), first[x] = tot;
e[++tot] = edge(first[y], x), first[y] = tot;
} #define y e[x].to
void dfs(int p) {
int x;
tr[p].sz = ;
for (x = first[p]; x; x = e[x].next)
if (y != tr[p].fa) {
tr[y].fa = p, tr[y].dep = tr[p].dep + ;
dfs(y);
tr[p].sz += tr[y].sz;
if (tr[tr[p].son].sz < tr[y].sz) tr[p].son = y;
}
} void DFS(int p) {
int x;
if (!tr[p].son) return;
tr[tr[p].son].top = tr[p].top, DFS(tr[p].son);
for (x = first[p]; x; x = e[x].next)
if (y != tr[p].fa && y != tr[p].son)
tr[y].top = y, DFS(y);
}
#undef y inline void Add_oper(int x, int y, int z) {
y = tr[y].son;
op[++tot_op] = oper(First[x], z, ), First[x] = tot_op;
op[++tot_op] = oper(First[y], z, -), First[y] = tot_op;
} inline void work(int x, int y, int z) {
while (tr[x].top != tr[y].top) {
if (tr[tr[x].top].dep < tr[tr[y].top].dep) swap(x, y);
Add_oper(tr[x].top, x, z);
x = tr[tr[x].top].fa;
}
if (tr[x].dep < tr[y].dep) swap(x, y);
Add_oper(y, x, z);
} void get_ans(int p) {
int x;
for (x = First[p]; x; x = op[x].next)
T -> modify(, Z, op[x].z, op[x].d);
ans[p] = T -> mx == ? : T -> wmx;
if (tr[p].son) get_ans(tr[p].son);
} int main() {
int i, x, y, z;
n = read(), m = read();
for (i = ; i < n; ++i) Add_Edges(read(), read());
dfs();
tr[].top = , DFS();
for (i = ; i <= m; ++i) {
x = read(), y = read(), z = read();
work(x, y, z);
}
T = new()seg;
for (i = ; i <= n; ++i)
if (tr[i].top == i) {
T -> clear();
get_ans(i);
}
for (i = ; i <= n; ++i)
printf("%d\n", ans[i]);
return ;
} inline int read() {
static int x;
static char ch;
x = , ch = getchar();
while (ch < '' || '' < ch)
ch = getchar();
while ('' <= ch && ch <= '') {
x = x * + ch - '';
ch = getchar();
}
return x;
}

(p.s. 窝比较懒,所以没有把颜色离散化,直接搞了动态开点线段树)

BZOJ3307 雨天的尾巴的更多相关文章

  1. [BZOJ3307] 雨天的尾巴(树上差分+线段树合并)

    [BZOJ3307] 雨天的尾巴(树上差分+线段树合并) 题面 给出一棵N个点的树,M次操作在链上加上某一种类别的物品,完成所有操作后,要求询问每个点上最多物品的类型. N, M≤100000 分析 ...

  2. [bzoj3307]雨天的尾巴_线段树合并

    雨天的尾巴 bzoj-3307 题目大意:N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最多的是哪种物品. ...

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

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

  4. [洛谷P4556][BZOJ3307]雨天的尾巴-T3订正

    线段树合并+树上差分 题目链接(···) 「简单」「一般」——其实「一般」也只多一个离散化 考试时想法看>这里< 总思路:先存所有的操作,离散化,然后用树上差分解决修改,用权值线段树维护每 ...

  5. [BZOJ3307]:雨天的尾巴(LCA+树上差分+权值线段树)

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

  6. bzoj3307 雨天的尾巴 题解(线段树合并+树上差分)

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

  7. bzoj3307雨天的尾巴(权值线段树合并/DSU on tree)

    题目大意: 一颗树,想要在树链上添加同一物品,问最后每个点上哪个物品最多. 解题思路: 1.线段树合并 假如说物品数量少到可以暴力添加,且树点极少,我们怎么做. 首先在一个树节点上标记出哪些物品有多少 ...

  8. bzoj3307 雨天的尾巴题解及改题过程(线段树合并+lca+树上差分)

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

  9. [BZOJ3307] 雨天的尾巴-----------------线段树进阶

    虽然是个板子,但用到了差分思想. Description N个点,形成一个树状结构.有M次发放,每次选择两个点x,y对于x到y的路径上(含x,y)每个点发一袋Z类型的物品.完成所有发放后,每个点存放最 ...

随机推荐

  1. STL--stack

    stack--概述: 栈(Stack)是一种特殊的线性表,只能在某一端插入和删除的特殊线性表.它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶.栈也称为先进后出表(LIFO). ...

  2. iOS - OC NSEnumerator 迭代器

    前言 @interface NSEnumerator<ObjectType> : NSObject <NSFastEnumeration> Xcode 7 对系统中常用的一系列 ...

  3. meta标签清理缓存

    如果需要在html页面上设置不缓存,这在<head>标签中加入如下语句: <meta http-equiv="Pragma" content="no-c ...

  4. maven核心概念4

    一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中唯一的一点. 1.2.Maven坐标主要组成 groupId:组织标识(包名) artifactId:项目名称 ver ...

  5. MyEclipse8.5启动无法选择工作空间的问题

    方法一:打开Window---Preferences---General---Startup and Shutdown,勾选Prompt for workspace on startup 选项,再次登 ...

  6. pkg-config问题:

    pkg-config是一个工具,可以用于检测相应的依赖环境. pkg-config用来检索系统中安装库文件的信息,典型的是用作库的编译和连接.一般来说,如果库的头文件不在/usr/include目录中 ...

  7. 【linux 命令】:查看系统开机,关机时间【转载】

    转载原文:http://www.cnblogs.com/kerrycode/p/3759395.html 看Linux开机关机时间的方法(非常全面) 1: who 命令查看 who -b 查看最后一次 ...

  8. Java Base64编码解码实现

    我尝试过两种方式:java自带的sun.misc的工具类,还有commons-codec.jar 1.sun.misc的工具类 String encoderStr = null; BASE64Enco ...

  9. asmca无法创建ASM磁盘

    现象 grid用户使用asmca无法创建asm磁盘,如下图 分析 如图所示,报错说是 Grid Infrastructure 出了问题.那么 Grid Infrastructure 是什么 ? 在安装 ...

  10. 最大堆的插入/删除/调整/排序操作(图解+程序)(JAVA)

    堆有最大堆和最小堆之分,最大堆就是每个节点的值都>=其左右孩子(如果有的话)值的完全二叉树.最小堆便是每个节点的值都<=其左右孩子值的完全二叉树. 设有n个元素的序列{k1,k2,..., ...