题解

不妨采取重链剖分的方式把路径剖成区间,然后用线段树维护,考虑如何合并一个区间

struct Node {
int lf, rg, tot;
}seg[N << 2]; int col[N << 2];
inline Node merge(const Node &lc, const Node &rc) {
if(!lc.tot) return rc;
if(!rc.tot) return lc;
Node ret = (Node){lc.lf, rc.rg, lc.tot + rc.tot};
if(lc.rg == rc.lf) --ret.tot;
return ret;
}

其中$Node$表示线段树中的一个节点,共有三个参数,左端点颜色,右端点颜色以及区间内颜色段数。$col$数组用于下方染色标记。

但是我们要考虑这个区间合并后是否存在相同的颜色其应该只有$1$的贡献却被记了$2$的贡献。这种情况存在当且仅当左区间的右端点颜色与右区间左端点颜色相同。

接着,有关于线段树的其他操作也没有什么好担心的了,接着考虑如何查询。

inline int doit(int x, int y) {
int fx = top[x], fy = top[y];
Node disx = (Node){0, 0, 0}, disy = (Node){0, 0, 0};
while(fx != fy) {
if(dep[fx] >= dep[fy]) disx = merge(query(dfn[fx], dfn[x]), disx), x = fa[fx], fx = top[x];
else disy = merge(query(dfn[fy], dfn[y]), disy), y = fa[fy], fy = top[y];
} if(dfn[x] > dfn[y]) swap(x, y), swap(disx, disy);
swap(disx.lf, disx.rg);
Node ret = merge(merge(disx, query(dfn[x], dfn[y])), disy);
return ret.tot;
}

由于重链剖分跳$top$时,两个端点的路径是独立的,所以不能像普通查询那样直接累加贡献,要分开处理,最后存在一个特殊情况,要将左区间的左右端点反置。(画图即可明白)

代码

#include <cstdio>
#include <algorithm>
using std::swap;
typedef long long ll; const int N = 1e5 + 10;
int n, m, c[N], w[N];
int fa[N], son[N], siz[N], dep[N];
int time, dfn[N], top[N];
int cnt, from[N], to[N << 1], nxt[N << 1];
struct Node {
int lf, rg, tot;
}seg[N << 2]; int col[N << 2]; void addEdge(int u, int v) {
to[++cnt] = v, nxt[cnt] = from[u], from[u] = cnt;
} void dfs(int u) {
dep[u] = dep[fa[u]] + 1, siz[u] = 1;
for(int i = from[u]; i; i = nxt[i]) {
int v = to[i]; if(v == fa[u]) continue;
fa[v] = u, dfs(v), siz[u] += siz[v];
if(siz[v] > siz[son[u]]) son[u] = v;
}
}
void dfs(int u, int t) {
dfn[u] = ++time, top[u] = t, w[time] = c[u];
if(!son[u]) return ; dfs(son[u], t);
for(int i = from[u]; i; i = nxt[i]) {
int v = to[i];
if(v != fa[u] && v != son[u])
dfs(v, v);
}
} inline Node merge(const Node &lc, const Node &rc) {
if(!lc.tot) return rc;
if(!rc.tot) return lc;
Node ret = (Node){lc.lf, rc.rg, lc.tot + rc.tot};
if(lc.rg == rc.lf) --ret.tot;
return ret;
}
inline void pushdown(int o, int lc, int rc) {
if(col[o]) {
seg[lc] = (Node){col[o], col[o], 1};
seg[rc] = (Node){col[o], col[o], 1};
col[lc] = col[rc] = col[o], col[o] = 0;
}
}
void build(int o = 1, int l = 1, int r = n) {
if(l == r) { seg[o] = (Node){w[l], w[l], 1}; return ; }
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
build(lc, l, mid), build(rc, mid + 1, r), seg[o] = merge(seg[lc], seg[rc]);
}
void color(int cl, int cr, int k, int o = 1, int l = 1, int r = n) {
if(l >= cl && r <= cr) {
seg[o] = (Node){k, k, 1}, col[o] = k;
return ;
}
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
pushdown(o, lc, rc);
if(cl <= mid) color(cl, cr, k, lc, l, mid);
if(cr > mid) color(cl, cr, k, rc, mid + 1, r);
seg[o] = merge(seg[lc], seg[rc]);
}
Node query(int ql, int qr, int o = 1, int l = 1, int r = n) {
if(l >= ql && r <= qr) return seg[o];
int mid = (l + r) >> 1, lc = o << 1, rc = lc | 1;
Node ret = (Node){0, 0, 0};
pushdown(o, lc, rc);
if(ql <= mid) ret = query(ql, qr, lc, l, mid);
if(qr > mid) ret = merge(ret, query(ql, qr, rc, mid + 1, r));
return ret;
} inline void upt(int x, int y, int k) {
int fx = top[x], fy = top[y];
while(fx != fy) {
if(dep[fx] >= dep[fy]) color(dfn[fx], dfn[x], k), x = fa[fx], fx = top[x];
else color(dfn[fy], dfn[y], k), y = fa[fy], fy = top[y];
} if(dfn[x] > dfn[y]) swap(x, y);
color(dfn[x], dfn[y], k);
}
inline int doit(int x, int y) {
int fx = top[x], fy = top[y];
Node disx = (Node){0, 0, 0}, disy = (Node){0, 0, 0};
while(fx != fy) {
if(dep[fx] >= dep[fy]) disx = merge(query(dfn[fx], dfn[x]), disx), x = fa[fx], fx = top[x];
else disy = merge(query(dfn[fy], dfn[y]), disy), y = fa[fy], fy = top[y];
} if(dfn[x] > dfn[y]) swap(x, y), swap(disx, disy);
swap(disx.lf, disx.rg);
Node ret = merge(merge(disx, query(dfn[x], dfn[y])), disy);
return ret.tot;
} int main () {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) scanf("%d", c + i);
for (int i = 1, u, v; i < n; ++i) {
scanf("%d%d", &u, &v);
addEdge(u, v), addEdge(v, u);
}
dfs(1), dfs(1, 1), build();
char opt; int a, b, c;
while(m--) {
scanf("\n%c%d%d", &opt, &a, &b);
if(opt == 'C') {
scanf("%d", &c);
upt(a, b, c);
} else printf("%d\n", doit(a, b));
}
return 0;
}

Luogu P2486 染色(树链剖分+线段树)的更多相关文章

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  9. 【BZOJ-2325】道馆之战 树链剖分 + 线段树

    2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 1153  Solved: 421[Submit][Statu ...

  10. POJ3237 (树链剖分+线段树)

    Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...

随机推荐

  1. [洛谷P4774] [NOI2018]屠龙勇士

    洛谷题目链接:[NOI2018]屠龙勇士 因为markdown复制过来有点炸格式,所以看题目请戳上面. 题解: 因为杀死一条龙的条件是在攻击\(x\)次,龙恢复\(y\)次血量\((y\in N^{* ...

  2. 【洛谷 P4934】 礼物 (位运算+DP)

    题目链接 位运算+\(DP\)=状压\(DP\)?(雾 \(a\&b>=min(a,b)\)在集合的意义上就是\(a\subseteq b\) 所以对每个数的子集向子集连一条边,然后答案 ...

  3. 移动端页面使用rem布局

    阿里团队的高清布局方案代码 所谓高清方案就是根据设备屏幕的DPR(设备像素比,又称DPPX,比如dpr=2时,表示1个CSS像素由4个物理像素点组成) 动态设置 html 的font-size, 同时 ...

  4. canvas_基于canvan绘制的双半圆环进度条

    效果图 实现原理: 1.使用canvas绘制两个半圆弧,底图灰色半圆弧和颜色进度圆弧. 2.利用setInterval计时器,逐步改变颜色进度条,达到进度条的效果. 效果代码: <!DOCTYP ...

  5. 转载:WebView

    前言 现在很多App里都内置了Web网页(Hyprid App),比如说很多电商平台,淘宝.京东.聚划算等等,如下图 那么这种该如何实现呢?其实这是Android里一个叫WebView的组件实现的.今 ...

  6. System and method to prioritize large memory page allocation in virtualized systems

    The prioritization of large memory page mapping is a function of the access bits in the L1 page tabl ...

  7. 算法题之Median of Two Sorted Arrays

    这道题是LeetCode上的题目,难度级别为5,刚开始做没有找到好的思路,以为是自己智商比较低,后来发现确实也比较低... 题目: There are two sorted arrays nums1  ...

  8. C基础 多用户分级日志库 sclog

    引言 - sclog 总的设计思路 sclog在之前已经内置到simplec 简易c开发框架中一个日志库. 最近对其重新设计了一下. 减少了对外暴露的接口. 也是C开发中一个轮子. 比较简单, 非常适 ...

  9. 设计模式之笔记--建造者模式(Builder)

    建造者模式(Builder) 定义 建造者模式(Builder),将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示. 类图 描述 Builder:定义一个建造者抽象类,以规范产 ...

  10. Tensorflow项目实战一:MNIST手写数字识别

    此模型中,输入是28*28*1的图片,经过两个卷积层(卷积+池化)层之后,尺寸变为7*7*64,将最后一个卷积层展成一个以为向量,然后接两个全连接层,第一个全连接层加一个dropout,最后一个全连接 ...