题目链接: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. JavaScript之HTML DOM Document 对象

    文档对象代表您的网页. 如果您希望访问 HTML 页面中的任何元素,那么您总是从访问 document 对象开始. 下面是一些如何使用 document 对象来访问和操作 HTML 的实例. 查找 H ...

  2. linux下监测进程是否存在

    因为有的统计脚本需要执行很久,而有不能总去人工的检查进程是否在跑,所以就用shell脚本来循环监测进程是否存在 尝试了网上说的$?表示上一条命令返回值总是达不到预期的结果,后来直接改成用一个变量记录返 ...

  3. mybatis-plus思维导图,让mybatis-plus不再难懂

    mybatis-plus与mybatis mybatis Mybatis 是一款优秀的持久层框架,它支持定制化 SQL.存储过程以及高级映射.MyBatis 避免了几乎所有的 JDBC 代码和手动设置 ...

  4. JS函数式编程 - 概念

    最近在看Typescript,顺便看了一些函数式编程,然后半个国庆假期就没有了.做个笔记,分几个部分写吧. 最开始接触函数式编程的时候,第一个接触的概念就是高阶函数,和柯里化.咋一看,这不就是长期用来 ...

  5. vue常用操作及学习笔记(路由跳转及路由传参篇)

    路由跳转 - 超链接方式跳转 html: <div id="app"> <h1>Hello App!</h1> <p> <!- ...

  6. [Vue CLI 3] 配置解析之 parallel

    官方文档中介绍过在 vue.config.js 文件中可以配置 parallel,作用如下: 是否为 Babel 或 TypeScript 使用 thread-loader. 该选项在系统的 CPU ...

  7. JS 鼠标键盘HTML事件

  8. 如何在Data Lake Analytics中使用临时表

    前言 Data Lake Analytics (后文简称DLA)是阿里云重磅推出的一款用于大数据分析的产品,可以对存储在OSS,OTS上的数据进行查询分析.相较于传统的数据分析产品,用户无需将数据重新 ...

  9. PSPP:顶替SPSS常用功能的优秀软件, Linux 下的经济学用软件

    几个替代SPSS的软体Salstat http://salstat.sourceforge.net/PSPP http://www.gnu.org/software/pspp/pspp.htmlR h ...

  10. Linux的一些简单命令操作总结

    防火墙 查看防火墙状态 systemctl status iptables (或service iptables status) 关闭防火墙 systemctl stop iptables(或serv ...