洛谷P2486 [SDOI2011]染色 题解 树链剖分+线段树
题目链接: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]染色 题解 树链剖分+线段树的更多相关文章
- 洛谷P3313 [SDOI2014]旅行 题解 树链剖分+线段树动态开点
题目链接:https://www.luogu.org/problem/P3313 这道题目就是树链剖分+线段树动态开点. 然后做这道题目之前我们先来看一道不考虑树链剖分之后完全相同的线段树动态开点的题 ...
- 【BZOJ2243】[SDOI2011]染色 树链剖分+线段树
[BZOJ2243][SDOI2011]染色 Description 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的 ...
- bzoj2243[SDOI2011]染色 树链剖分+线段树
2243: [SDOI2011]染色 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 9012 Solved: 3375[Submit][Status ...
- B20J_2243_[SDOI2011]染色_树链剖分+线段树
B20J_2243_[SDOI2011]染色_树链剖分+线段树 一下午净调这题了,争取晚上多做几道. 题意: 给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成 ...
- 洛谷P4092 [HEOI2016/TJOI2016]树 并查集/树链剖分+线段树
正解:并查集/树链剖分+线段树 解题报告: 传送门 感觉并查集的那个方法挺妙的,,,刚好又要复习下树剖了,所以就写个题解好了QwQ 首先说下并查集的方法趴QwQ 首先离线,读入所有操作,然后dfs遍历 ...
- 2243: [SDOI2011]染色 树链剖分+线段树染色
给定一棵有n个节点的无根树和m个操作,操作有2类: 1.将节点a到节点b路径上所有点都染成颜色c: 2.询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段), 如“112221”由3段组 ...
- BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)
题目链接 BZOJ2243 树链剖分 $+$ 线段树 线段树每个节点维护$lc$, $rc$, $s$ $lc$代表该区间的最左端的颜色,$rc$代表该区间的最右端的颜色 $s$代表该区间的所有连续颜 ...
- 【bzoj1959】[Ahoi2005]LANE 航线规划 树链剖分+线段树
题目描述 对Samuel星球的探险已经取得了非常巨大的成就,于是科学家们将目光投向了Samuel星球所在的星系——一个巨大的由千百万星球构成的Samuel星系. 星际空间站的Samuel II巨型计算 ...
- BZOJ2243 (树链剖分+线段树)
Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. ...
随机推荐
- ubuntu安装verilog
1.安装verilog sudo apt-get install verilog 2.安装gtkwave sudo apt-get install gtkwave 3.安装dinotrace(和gtk ...
- OpenCV灰度化图像
OpenCV2版本号非常多函数发生了变化.比如二值化,其演示样例: void CmyMFC2Dlg::OnBnClickedButton1() { // TODO: Add your control ...
- UI标签库专题五:JEECG智能开发平台 Tabs(选项卡父标签)
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/zhangdaiscott/article/details/28956223 tools string ...
- BZOJ 4420二重镇题解
链接 思路借鉴了这个博客: 我们可以想到状压dp 用一个十进制数来表示状态,即第i位表示位置i处的物品等级 用f[i][j][k]表示第i天,仓库的物品等级为j,状态为k时的最大收益 但是状态数貌似很 ...
- 使用帝国备份王软件提示 Parse error: syntax error, unexpected end of file
使用帝国备份王软件提示 Parse error: syntax error, unexpected end of file时, 可以尝试一下方法: 1.php.ini要把short_open_tag ...
- 【JZOJ4747】【NOIP2016提高A组模拟9.3】被粉碎的线段树
题目描述 输入 第一行包括两个正整数,N ,M ,分别表示线段树的宽以及询问次数. 以下N-1 行以先序遍历(dfs深搜顺序)描述一个小R线段树,每行一个正整数表示当前非叶子节点的 mid,保证每个节 ...
- Failed to delete access_log
重复build 关闭已经开启的tomcat terminal 再次开启即可
- hdu5131 贪心
#include<stdio.h> #include<string.h> #include<algorithm> #include<string> #i ...
- oracle表复杂查询--创建数据库实例
n 创建数据库有两种方法: 1)通过oracle提供的向导工具 2)我们可以用手工步骤直接创建 但我们创建完一个新的数据库实例后,在服务中就会有两个新的服务创建,这时,你根据实际需要去启动相应的数据 ...
- 配置上这个模板Bug少90%
本来写程序经常会碰到各种难缠的Bug,自从修改了注释模板,bug明显少了,看效果图: 好吧,我逗比了 下面是文字版: /** _oo0oo_ o8888888o 88" . "88 ...