QTREE5 - Query on a tree V【LCT】

2023-11-05

题目链接


你被给定一棵n个点的树,点从1到n编号。每个点可能有两种颜色:黑或白。我们定义dist(a,b)为点a至点b路径上的边个数。

一开始所有的点都是黑色的。

要求作以下操作:

0 i 将点i的颜色反转(黑变白,白变黑)

1 v 询问dist(u,v)的最小值。u点必须为白色(u与v可以相同),显然如果v是白点,查询得到的值一定是0。

特别地,如果作'1'操作时树上没有白点,输出-1。


动态点分治解决该问题


LCT解法

  我们知道LCT实际上是多个Splay的森林,它有实虚边之分,实边的贡献是很好记录的,而虚边需要我们在用堆或者一些数据结构来进行维护。

  参考了网上的一些思维的方式,我假设这棵树的实际的根为“1”,也就是我假定原树的根是“1”,那么对于其余的点,我们将边的权值赋值到点上去,也就是dfs之后,是u \rightarrow v,那么就给v点权值为“1”,因为本题是单位边权。

  假设不改变树的实际根,也就是我们不会让makeroot()这个函数出现,保证了整棵树的深度,就是LCT中Spay的子树的“左中右”的遍历顺序。

  那我维护这样的两个东西:

lmn[x]:表示在Splay图中,以x为子树的根的时候的最浅的结点所能到达的白点的最近距离。

rmn[x]:表示在Splay图中,以x为子树的根的时候的最深的结点所能到达的白点的最近距离。

于是,我们可以试着列写pushup方程。

  • lmn[x]
  1. 可以是通过左儿子(深度比他浅的结点)直接继承它的lmn[x],也就是lmn[lc]
  2. 也有可能是自己本身,如果要算上自己的话,说明要经过从原图中x的父亲到x的这条边了,所以要把x结点的权值加上来;
  3. 是从深度最浅的点,去找到它(x)的右子树上的点所能到达的最近的白点,那么应该去找rc(右子结点)为根的Splay子树上最浅的点所能到达的最近白点,距离和就是size[lc] + val[x] + lmn[rc],size[lc]是x的最浅点到x的距离,val[x]是因为要从x的父亲走到x了,所以会加上x的距离,通过size[lc] + val[x]就可以保证最浅的结点能到达x点了,lmn[rc]是rc的Splay子树中最浅的点能到达的最近白点,因为它们是一条链上的,所以就不需要担心。
  4. 另外,不要忘记对虚边的处理,我们可以用一个堆将所有的lmn[x]存起来,然后与“3操作”类似,变成了size[lc] + val[x] + s[x].top()即可。

  关于lmn[x]的补充部分,我在这里算的,实际上有的lmn[x]是多算了,因为有的点是算上了它到原树中父亲的距离,所以在做比较的时候,要分析清晰。

  • rmn[x]
  1. 首先,肯定是要看能不能继承原来rs的值,也就是rmn[rc];
  2. 依然有可能是到自己本身的,那么此时由于是从深度更深的点过来的,所以就不用加val[x]了,变成了size[rc] + w[x]
  3. 要是遇到要经过x点去lc查找的时候呢,就会经过x,去往另一个方向了,此时距离x最近的点就是rmn[ls]对应的点了,因为x与x最接近的肯定就是深度深的,左子树中深度最深的就是了,于是就是size[rc] + val[x] + rmn[lc]
  4. 最后,不要忘记的是虚边,与x相连的虚边,那么就是去找堆中的最小值,因为是不经过val[x]的边的,所以这里不要加v al[x],是size[rc] + s[x].top()

  最后,我们要查询的对吧,查询怎么查?将要查询的点作为深度最深的结点,也就是将它access到根之后,Splay到root,那么它的rmn[x]就是我们要查询的答案了,因为rmn[x]维护的是Splay子树中最深的点到最近白点的距离。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
//const int maxN = 11;
int N, Q, white, c[maxN][2], r[maxN], fa[maxN], size[maxN], col[maxN], lmn[maxN], rmn[maxN], w[maxN], val[maxN];
struct heap
{
    priority_queue<int, vector<int> , greater<int> > Que, Del;
    inline bool empty()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        return Que.empty();
    }
    inline void push(int val) { Que.push(val); }
    inline void clear(int val) { Del.push(val); }
    inline int size() { return (int)(Que.size() - Del.size()); }
    inline int top()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        return !Que.empty() ? Que.top() : INF;
    }
    inline void pop()
    {
        while(!Que.empty() && !Del.empty() && Que.top() == Del.top()) { Que.pop(); Del.pop(); }
        Que.pop();
    }
} s[maxN];
inline bool isroot(int x) { return c[fa[x]][0] != x && c[fa[x]][1] != x; }
inline void pushup(int x)
{
    if(!x) return;
    size[x] = size[c[x][0]] + size[c[x][1]] + val[x];
    lmn[x] = min(lmn[c[x][0]], size[c[x][0]] + min(w[x], min(s[x].top(), lmn[c[x][1]])) + val[x]);
    rmn[x] = min(rmn[c[x][1]], size[c[x][1]] + min(w[x], min(s[x].top(), rmn[c[x][0]] + val[x])));
}
inline void pushr(int x)
{
    if(!x) return;
    swap(c[x][0], c[x][1]);
    r[x] ^= 1;
}
inline void pushdown(int x)
{
    if(!x) return;
    if(r[x])
    {
        pushr(c[x][0]);
        pushr(c[x][1]);
        r[x] = 0;
    }
}
void Rotate(int x)
{
    int y = fa[x], z = fa[y], k = c[y][1] == x, cop = c[x][k ^ 1];
    if(!isroot(y)) c[z][c[z][1] == y] = x;
    fa[x] = z;
    c[y][k] = cop;
    fa[cop] = y;
    c[x][k ^ 1] = y;
    fa[y] = x;
    pushup(y); pushup(x);
}
int Stap[maxN];
void Splay(int x)
{
    int y = x, z = 0;
    Stap[++z] = y;
    while(!isroot(y)) Stap[++z] = y = fa[y];
    while(z) pushdown(Stap[z--]);
    while(!isroot(x))
    {
        y = fa[x]; z = fa[y];
        if(!isroot(y)) (c[z][0] == y) ^ (c[y][0] == x) ? Rotate(x) : Rotate(y);
        Rotate(x);
    }
}
void access(int x)
{
    int y = 0;
    while(x)
    {
        Splay(x);
        if(c[x][1]) s[x].push(lmn[c[x][1]]);
        if(y) s[x].clear(lmn[y]);
        c[x][1] = y;
        pushup(x);
        y = x; x = fa[x];
    }
}
int head[maxN], cnt;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN << 1];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void dfs(int u, int father)
{
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == father) continue;
        fa[v] = u; val[v] = 1;
        dfs(v, u);
        s[u].push(lmn[v]);
    }
    pushup(u);
}
void update(int x)
{
    access(x);
    Splay(x);
    col[x] ^= 1;
    w[x] = col[x] ? 0 : INF;
    if(col[x]) white++;
    else white--;
    pushup(x);
}
inline int query(int x)
{
    access(x); Splay(x);
    return rmn[x];
}
inline void init()
{
    white = 0; lmn[0] = rmn[0] = INF;
    for(int i=1; i<=N; i++)
    {
        r[i] = 0; c[i][0] = c[i][1] = 0; head[i] = -1; col[i] = 0;
        size[i] = 1;
        lmn[i] = rmn[i] = w[i] = INF;
    }
}
int main()
{
    scanf("%d", &N);
    init();
    for(int i=1, u, v; i<N; i++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    val[1] = 0;
    dfs(1, 0);
    scanf("%d", &Q);
    int op, x;
    while(Q--)
    {
        scanf("%d%d", &op, &x);
        if(!op)
        {
            update(x);
        }
        else
        {
            if(!white) printf("-1\n");
            else printf("%d\n", query(x));
        }
    }
    return 0;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

QTREE5 - Query on a tree V【LCT】 的相关文章

  • vue项目请求控制请求头必须为https

    前言 因为很多项目必须要求是严格模式 不能有http请求 需要限制我们的请求头必须为https 如果是http的话 手动转成https来实现请求效果 实现方法 在 public index html 的 head 标签里面加入以下代码 效果
  • Step4:Angular调试方法

    1 方法一 采用VSCode编译器 下载插件debugger for chrome 选择调试 然后再选择chrome浏览器 在运行中输入npm start执行 就可以在代码中打断点了 2 方法二 在浏览器中按F12打开开发者工具 Sourc
  • Python第二课

    枭 Python第二课 今天讲解了Python的 内置函数 模块导入 序列 列表 切片操作 内置函数 divmod x y 用法 x y divmod a b 其中x返回值a b y返回值a b map func iterablies 用法
  • 4g网络设置dns地址_4G网速越来越慢,通过这三个简单的操作,网速成倍提升

    随着互联网的进步 从零几年开始移动手机在全国开始普及起来 网速也像火箭一样快速飙升 从2G发展到了现在的5G 不过 有很多网友表示 刚从2G或者3G升级到4G时 网速体验非常好 但近两年来的4G网速越来越慢 还卡顿 甚至感觉还不如以前的3g
  • 忘记网站服务器密码怎么办,忘记远程服务器的密码怎么办

    忘记远程服务器的密码怎么办 内容精选 换一换 如果在创建弹性云服务器时未设置密码 或密码丢失 过期 可以参见本节操作重置密码 密码丢失或过期前 已安装密码重置插件 公共镜像创建的弹性云服务器默认已安装一键重置密码插件 私有镜像创建的云服务器
  • Matlab—M_Map的实战学习笔记(一)M_Map库的安装

    最近在做美赛集训 做到了2020年的美赛A题 有关苏格兰附近鲭鱼和鲱鱼分布预测问题 在写论文的过程中 为了画几张精美的地图 可谓是历经千难万险 花费了不少时间 走了不少弯路 现在对使用matlab的m map映射库进行地图绘制做一个总结 力
  • Python:UnicodedecodeError编码问题解决方法汇总-彻底解决

    今天真的被编码问题一直困扰着 午休都没进行 也真的见识到了各种编码 例如 gbk unicode utf 8 ansi gb2312等 如果脚本程序中编码与文件编码不一致 就会报出UnicodedecodeError的错误 1 情景一 读文
  • python语法-面向对象(构造方法、魔术方法)

    python语法 面向对象 构造方法 魔术方法 1 构造方法 构造方法 python类可以使用 init 方法 称之为构造方法 可以实现 在创建类对象时 会自动执行 在创建类对象时 将传入参数自动传递给 init 方法使用 演示使用构造方法
  • Android中的定时器Timer、AlarmManager、CountDownTimer的使用

    1 Timer和TimerTask的使用 java util Timer定时器 实际上是个线程 定时调度所拥有的TimerTasks 1 创建一个Timer code class hljs cs has numbering style di
  • 解析 Linux 内核可装载模块的版本检查机制

    解析 Linux 内核可装载模块的版本检查机制 王 华东 系统工程师 自由职业者 简介 为保持 Linux 内核的稳定与可持续发展 内核在发展过程中引进了可装载模块这一特性 内核可装载模块就是可在内核运行时加载到内核的一组代码 通常 我们会
  • js获取到的时间减1秒或加1秒

    如题 使用时间戳来计算 function setDate time isAdd var date getCurTime time 也可以直接透传如 2021 5 8 var d new Date date var t s d getTime

随机推荐

  • 闲鱼把各种玩法做成了一个平台:哆啦A梦

    玩法平台背景 在闲鱼内我们把供给用户的闲鱼红包 支付宝红包 包邮券 宝卡等统称为用户权益 是闲鱼用户运营的重要策略 在拉新 留存 促活 裂变等方面都展现了其重要价值 在阿里内部管理权益的平台是拉菲 拉菲对外提供概率抽奖和领奖两种能力 各个业
  • 为什么gbk编码常用抽取正则表达式无法抽取“嘚瑟“的“嘚”字

    根据 GBK汉字内码扩展规范编码表 http ff 163 com newflyff gbk list 可以查到 嘚 字的编码为874e 而我们常用的gbk汉字抽取正则表达式为 x80 xff x80 xff 以python正则为例 抽取汉
  • Python基础--入门基础和数据类型测试题(二)

    Made By Zly All Right Reversed 上一篇 篇四 Python 入门基础和数据类型测试题 二 1 以下不属于Python语言保留字的是 A do B pass C while D def 2 表达式3 4 2 8
  • 第一讲 检索系统与数据库编程

    第一讲 检索系统与数据库编程 准备工作 1 检索系统 1 1 检索系统初识 1 1 1 什么是检索系统 1 1 2 从认知心理学看待检索系统 1 2 检索系统的四大法宝 1 2 1 检索的工具 结构化查询语言 SQL 1 2 2 检索的环境
  • Electron-builder打包和自动更新

    前言 文本主要讲述如何为 electron 打包出来软件配置安装引导和结合 github 的 release 配置自动更新 electron builder 是将 Electron 工程打包成相应平台的软件的工具 我的工程是使用 elect
  • C语言小知识点

    1 LPCSTR被定义成是一个指向以 0 结尾的常量字符指针 LPWSTR是wchar t字符串 例子 LPWSTR lpwstr NULL LPWSTR lp T asdfasgaf 2 之所以能够实现条件编译是因为预编译指令是在编译之前
  • HTTP请求头和响应头详解【转】

    最近老猿在开始学习爬虫相关的知识 由于老猿以前只做非web的后台应用 发现相关知识太过匮乏 导致学习很困难 为此不得不从一些基础知识恶补开始 对于这些知识 老猿会将网上找到的比较认可的内容直接转发 下面文章关于http头部信息讲解的非常详细
  • springboot笔记总结

    springboot 1 Javaconfig Configuration 放在类的上面 这个类相当于 xml 配置文件 可以在其中声明 bean Bean 放在方法的上面 方法的返回值是对象类型 这个对象注入到 spring ioc 容器
  • 字典排序算法(通俗易懂)

    我们先看一个例子 示例 1 2 3的全排列如下 1 2 3 1 3 2 2 1 3 2 3 1 3 1 2 3 2 1 我们这里是通过字典序法找出来的 那么什么是字典序法呢 从上面的全排列也可以看出来了 从左往右依次增大 对这就是字典序法
  • Java中 ? extends T 和 ? super T 的理解

    通配符类型
  • (转)如何有效地管理好技术团队?

    转自 https cn 100offer com blog posts 307 技术管理是一个综合性岗位 要求你具有技术能力 管理能力 也要懂一些心理学 情商也要高一些 说实话 你想做好这个岗位 真的不容易 尤其是在中国 我相信今天的分享过
  • 策略+工厂+反射记录一次switch代码简化过程

    遇到的问题 一张记录表 记录了10个业务的字段 一个入参type说明了要修改哪个字段 最初是通过switch type case 来做的 但是涉及这样子的判断多了 每次都要不断的switch 并且case里面不同方法有不同的处理 一个公共的
  • 河南省历年高考人数(2004-2021)

    河南省历年高考人数 2004 2021 年份 人数 万人 2004 59 55 2005 72 2006 78 2007 87 88 2008 98 8 2009 95 9 2010 95 24 2011 85 5 2012 80 5 20
  • 系统还原服务器,服务器系统还原

    服务器系统还原 内容精选 换一换 1 说明2 制作系统还原盘3 测试恢复还原1 说明http clonezilla nchc org tw clonezilla live download clonezilla live 2 6 7 28
  • 单调队列的学习 - 滑动窗口求最大/小值 (Leetcode 239, Sliding Window Maximum)

    这几天在学习单调队列和单调栈 感觉下面几篇博客讲的比较好 http www cnblogs com saywhy p 6726016 html http dping26 blog 163 com blog static 1795662172
  • 基于UDP实现双工通信(JAVA)(多线程)

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 前言 总结 前言 写个基础的JAVA网络程序 实现双工通信 一 两个类 1 一个累 代码如下 示例 import java io IOException impor
  • 【华为OD统一考试A卷

    华为OD统一考试A卷 B卷 新题库说明 2023年5月份 华为官方已经将的 2022 0223Q 1 2 3 4 统一修改为OD统一考试 A卷 和OD统一考试 B卷 你收到的链接上面会标注A卷还是B卷 请注意 根据反馈 目前大部分收到的都是
  • 合并日志树——LSM Tree

    一 背景 大数据情景下 需要巨量的读写数据 即良好的IO效率 传统的B树以及其变种无法满足 因为它的读写在物理上是随机的 这样IO的效率就不高 于是便有了LSM log structed merge tree 合并日志树这个设计思想或者说存
  • Latex字体加粗

    You latex 字体加粗 什么代码 ChatGPT 在 LaTeX 中 要使文本加粗 可以使用 textbf 命令或 bfseries命令 以下是示例代码 使用 textbf 命令 textbf This is bold text 使用
  • QTREE5 - Query on a tree V【LCT】

    题目链接 你被给定一棵n个点的树 点从1到n编号 每个点可能有两种颜色 黑或白 我们定义dist a b 为点a至点b路径上的边个数 一开始所有的点都是黑色的 要求作以下操作 0 i 将点i的颜色反转 黑变白 白变黑 1 v 询问dist