BZOJ 2243 浅谈树链剖分+线段树

本文介绍了如何使用树链剖分和线段树解决一个关于无根树的染色及颜色段查询问题。在1e5的数据规模下,通过树链剖分将树转化为序列,并利用线段树进行区间维护和查询,复杂度为mlog^2。文章详细阐述了算法思路,包括如何处理染色操作和避免重复计数,以及完整代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这里写图片描述
世界真的很大
前几次考试有一次树链剖分当场写挂之后调了一下午
一直耿耿于怀,于是乎找一道树链剖分的题来练手
虽然代码量略大但是调试起来还是比较轻松,一个小错误卡了一会儿
没搞明白root根本没有赋值为什么还能过样例
一直RE加上return就A了

看题先:

description:

给定一棵有n个节点的无根树和m个操作,操作有2类:
1、将节点a到节点b路径上所有点都染成颜色c;
2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),如“ 112221 ” 由3段组成:“ 11 ” 、“ 222 ” 和“ 1 ” 。
请你写一个程序依次完成这m个操作。

input:

第一行包含2个整数n和m,分别表示节点数和操作数;
第二行包含n个正整数表示n个节点的初始颜色
下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
下面 行每行描述一个操作:
“C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
“Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

output:

对于每个询问操作,输出一行答案。

树上链修改和查询,1e5的数据范围,应该能想到树链剖分
树链剖分的目的主要是为了那个特殊的DFS序,不光满足子树的DFS序是连续的一段,还满足一条重链上的点的dfs序是连续的一段
重链就是指子树最大的子节点所组成的链

这样就把“树”这么一个图抽象成了序列,然后就可以用数据结构维护序列的信息,然后通过序列与树的关系来得到答案

树上的链可以由一条条重链的一部分拆分得到,而重链由在DFS序上是连续的一段,所以可以用线段树来维护。
由于一条链最多被拆分成log条重链,而一次线段树查询时log的,那么一次链询问就是log^2的,总复杂度就是mlog^2的

这道题我们求的是链上有多少颜色段,那么线段树的一个区间就保存颜色段的数量,由于树上链会被拆分,于是乎会多次查询线段,有可能两条线段拼起来会形成一段颜色,这样就会重复计数。所以想到再记录一下每个线段两个端点的颜色,如果上一条线段的做断电与这一条线段的右端点相等的话,ans就–

还有染色操作,就是区间覆盖,搞一个标记flag,在查询时注意pushdown就行了,还是比较好写

完整代码:

#include<stdio.h>
#include<algorithm>
using namespace std;

struct edge
{
    int v,last;
}ed[400010];

struct node
{
    int sum,lc,rc,flag;
    node *ls,*rs;
    void pushdown()
    {
        if(flag)
        {
            ls->sum=rs->sum=1;
            ls->flag=rs->flag=flag;
            ls->lc=ls->rc=lc;
            rs->
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值