题目链接:https://www.luogu.org/problem/P2486

首先这是一道树链剖分+线段树的题。

线段树部分和 codedecision P1112 区间连续段 一模一样,所以我们在做这道题目之前最好去做一下这道题目的练习。

然后就是树链剖分的部分。

此部分支持两种操作:

  • 更新:这部分比较好实现;
  • 查询:这部分需要你记录树链查询的时候的每一条边的信息,然后将这些信息进行汇总,处理起来稍有一些繁琐。

实现代码如下:

#include <bits/stdc++.h>
using namespace std;
#define INF (1<<29)
const int maxn = 100010;
int fa[maxn],
dep[maxn],
size[maxn],
son[maxn],
top[maxn],
seg[maxn], seg_cnt,
rev[maxn];
vector<int> g[maxn];
void dfs1(int u, int p) {
size[u] = 1;
for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
int v = (*it);
if (v == p) continue;
fa[v] = u;
dep[v] = dep[u] + 1;
dfs1(v, u);
size[u] += size[v];
if (size[v] >size[son[u]]) son[u] = v;
}
}
void dfs2(int u, int tp) {
seg[u] = ++seg_cnt;
rev[seg_cnt] = u;
top[u] = tp;
if (son[u]) dfs2(son[u], tp);
for (vector<int>::iterator it = g[u].begin(); it != g[u].end(); it ++) {
int v = (*it);
if (v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
struct Node {
int l, r, cnt;
Node () {}
Node (int _l, int _r, int _cnt) { l = _l; r = _r; cnt = _cnt; }
Node reverse() { return Node(r, l, cnt); }
} tree[maxn<<2];
int n, lazy[maxn<<2], init_color[maxn];
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
void push_up(int rt) {
tree[rt].l = tree[rt<<1].l;
tree[rt].r = tree[rt<<1|1].r;
tree[rt].cnt = tree[rt<<1].cnt + tree[rt<<1|1].cnt - (tree[rt<<1].r == tree[rt<<1|1].l ? 1 : 0);
}
void push_down(int rt) {
if (lazy[rt]) {
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
tree[rt<<1].cnt = tree[rt<<1|1].cnt = 1;
tree[rt<<1].l = tree[rt<<1].r = tree[rt<<1|1].l = tree[rt<<1|1].r = lazy[rt];
lazy[rt] = 0;
}
}
void build(int l, int r, int rt) {
if (l == r) {
tree[rt] = Node(init_color[rev[l]], init_color[rev[l]], 1);
return;
}
int mid = (l + r) / 2;
build(lson);
build(rson);
push_up(rt);
}
void update(int L, int R, int v, int l, int r, int rt) {
if (L <= l && r <= R) {
tree[rt] = Node(v, v, 1);
lazy[rt] = v;
return;
}
push_down(rt);
int mid = (l + r) / 2;
if (L <= mid) update(L, R, v, lson);
if (R > mid) update(L, R, v, rson);
push_up(rt);
}
Node query(int L, int R, int l, int r, int rt) {
if (L <= l && r <= R) return tree[rt];
push_down(rt);
int mid = (l + r) / 2;
if (L > mid) return query(L, R, rson);
else if (R <= mid) return query(L, R, lson);
else {
Node a = query(L, R, lson);
Node b = query(L, R, rson);
return Node(a.l, b.r, a.cnt + b.cnt - (a.r == b.l ? 1 : 0));
}
} void chain_update(int u, int v, int val) {
while (top[u] != top[v]) {
if (dep[top[u]] < dep[top[v]]) swap(u, v);
update(seg[top[u]], seg[u], val, 1, n, 1);
u = fa[top[u]];
}
if (dep[u] < dep[v]) swap(u, v);
update(seg[v], seg[u], val, 1, n, 1);
}
vector<Node> res1, res2, res;
void chain_query(int u, int v) {
res1.clear();
res2.clear();
res.clear();
while (top[u] != top[v]) {
if (dep[top[u]] > dep[top[v]]) {
res1.push_back(query(seg[top[u]], seg[u], 1, n, 1));
u = fa[top[u]];
}
else {
res2.push_back(query(seg[top[v]], seg[v], 1, n, 1));
v = fa[top[v]];
}
}
if (dep[u] > dep[v]) res1.push_back(query(seg[v], seg[u], 1, n, 1));
else res2.push_back(query(seg[u], seg[v], 1, n, 1));
int sz = res1.size();
for (int i = 0; i < sz; i ++) res.push_back(res1[i].reverse());
sz = res2.size();
for (int i = sz-1; i >= 0; i --) res.push_back(res2[i]);
Node tmp = res[0];
sz = res.size();
for (int i = 1; i < sz; i ++) {
int delta = (tmp.r == res[i].l);
tmp.cnt += res[i].cnt - delta;
tmp.r = res[i].r;
}
cout << tmp.cnt << endl;
} int m, a, b, c;
char op[2];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> init_color[i];
for (int i = 1; i < n; i ++) {
int u, v;
cin >> u >>v;
g[u].push_back(v);
g[v].push_back(u);
}
dep[1] = fa[1] = 1;
dfs1(1, -1);
dfs2(1, 1);
build(1, n, 1);
while (m --) {
cin >> op;
if (op[0] == 'C') {
cin >> a >> b >> c;
chain_update(a, b, c);
}
else {
cin >> a >> b;
chain_query(a, b);
}
}
return 0;
}

洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树的更多相关文章

  1. 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点

    题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...

  2. 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树

    [BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...

  3. bzoj2243[SDOI2011]染色 树链剖分+线段树

    2243: [SDOI2011]染色 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 9012  Solved: 3375[Submit][Status ...

  4. B20J_2243_[SDOI2011]染色_树链剖分+线段树

    B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...

  5. 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树

    正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...

  6. 2243: [SDOI2011]染色 树链剖分+线段树染色

    给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...

  7. BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)

    题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...

  8. 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树

    题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...

  9. BZOJ2243 (树链剖分+线段树)

    Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...

随机推荐

  1. shared_from_this bad_weak_ptr的原因

    原因:创建类A的对象的时候没有用智能指针包裹,而是直接new的裸指针. enable_from_this 的使用与实现原理说明: shared_from_this()是enable_shared_fr ...

  2. ScrollView 实现子视图滑动到顶部时固定不动

    这个,个人建议使用自己写的布局使用view的gon或者visble的方法,使用design包中的控件来的话,局限性很大 方法有倆 (1)自定义ScrollView 重写ScrollView 的 com ...

  3. LintCode_175 翻转二叉树

    题目 翻转一棵二叉树 您在真实的面试中是否遇到过这个题? Yes 样例 1 1 / \ / \ 2 3 => 3 2 / \ 4 4 和前序遍历代码很相似从叶子节点依次翻转递归到根节点C++代码 ...

  4. 项目管理知识图谱OR架构图

    做项目管理,心中一定要有知识图谱,科学的知识储备+100%执行力=好的管理者. 德鲁克所言:  领导是“做正确的事”,管理是“把事做正确”.

  5. JavaScript--函数表达式与函数声明的区别

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  6. SQLServer —— 视图

    一.视图的概念 是存储在服务器端的一个查询块,是一张虚拟表. 表示一张表的部分数据或多张表的综合数据. 其结构和数据是建立在对表的查询基础上. 视图的使用,跟对普通的表的查询使用完全一样. 二.视图中 ...

  7. sping,springMVC @Component 注解的对象都是单例模式,变量不能全局

    错误方式:      将属性和变量定义为全局,单例模式,所有人共享,导致所有人的数据都发生错误! 正确方式 一:    将变量定义到局部,互不影响. 正确方式 二:      假如必须放到全局所有方法 ...

  8. fedora 安装 pidgin-lwqq

    因为 腾讯自带的linux for  qq 已经无法登陆,于是详尽各种办法在fedora 上安装 qq ,但均以失败高中.于是使用了几天web qq 但最终无法忍受,于是有研究起来了 pidgin-l ...

  9. Directx11教程(17) D3D11管线(6)

    原文:Directx11教程(17) D3D11管线(6)       VS shader输出clip空间的顶点位置及参数信息(比如颜色)到一个FIFO中,之后PA(primitive assembl ...

  10. linux 查看并关闭窗口

    查看端口 ps -ef | grep tomcat 关闭端口 kill -9 端口号