给你一棵 n 个节点的树,编号从 0 到 n - 1 ,以父节点数组 parent 的形式给出,其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点,所以 parent[0] = -1 ,因为它没有父节点。你想要设计一个数据结构实现树里面对节点的加锁,解锁和升级操作。

数据结构需要支持如下函数:

  • Lock:指定用户给指定节点 上锁 ,上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下,才能进行上锁操作。
  • Unlock:指定用户给指定节点 解锁 ,只有当指定节点当前正被指定用户锁住时,才能执行该解锁操作。
  • Upgrade:指定用户给指定节点 上锁 ,并且将该节点的所有子孙节点 解锁 。只有如下 3 个条件 全部 满足时才能执行升级操作:
  1. 指定节点当前状态为未上锁。
  2. 指定节点至少有一个上锁状态的子孙节点(可以是 任意 用户上锁的)。
  3. 指定节点没有任何上锁的祖先节点。
    请你实现 LockingTree 类:
LockingTree(int[] parent) 用父节点数组初始化数据结构。
lock(int num, int user) 如果 id 为 user 的用户可以给节点 num 上锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 id 为 user 的用户 上锁 。
unlock(int num, int user) 如果 id 为 user 的用户可以给节点 num 解锁,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 变为 未上锁 状态。
upgrade(int num, int user) 如果 id 为 user 的用户可以给节点 num 升级,那么返回 true ,否则返回 false 。如果可以执行此操作,节点 num 会被 升级 。

示例 1:


输入:
["LockingTree", "lock", "unlock", "unlock", "lock", "upgrade", "lock"]
[[[-1, 0, 0, 1, 1, 2, 2]], [2, 2], [2, 3], [2, 2], [4, 5], [0, 1], [0, 1]]
输出:
[null, true, false, true, true, true, false]解释:
LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]);
lockingTree.lock(2, 2);    // 返回 true ,因为节点 2 未上锁。// 节点 2 被用户 2 上锁。
lockingTree.unlock(2, 3);  // 返回 false ,因为用户 3 无法解锁被用户 2 上锁的节点。
lockingTree.unlock(2, 2);  // 返回 true ,因为节点 2 之前被用户 2 上锁。// 节点 2 现在变为未上锁状态。
lockingTree.lock(4, 5);    // 返回 true ,因为节点 4 未上锁。// 节点 4 被用户 5 上锁。
lockingTree.upgrade(0, 1); // 返回 true ,因为节点 0 未上锁且至少有一个被上锁的子孙节点(节点 4)。// 节点 0 被用户 1 上锁,节点 4 变为未上锁。
lockingTree.lock(0, 1);    // 返回 false ,因为节点 0 已经被上锁了。

提示:

  • n == parent.length
  • 2 <= n <= 2000
  • 对于 i != 0 ,满足 0 <= parent[i] <= n - 1
  • parent[0] == -1
  • 0 <= num <= n - 1
  • 1 <= user <= 104
  • parent 表示一棵合法的树。
  • lock ,unlock 和 upgrade 的调用 总共 不超过 2000 次。

解题思路

使用map维护被锁节点和加锁者的关系,再使用一个map维护父节点和对应子节点之间的关系

lock

判断是否有锁,如果没有,则可以直接加锁

unlock

判断当前锁的加锁者是否为自己

upgrade

  1. 先向上遍历祖先节点和加锁节点,判断是否有加锁
  2. 再遍历子孙节点,判断是否加锁
  3. 给所有子孙节点解锁,给当前节点加锁

代码

    class LockingTree {int[] p;Map<Integer, Integer> locked = new HashMap<>();Map<Integer,Set<Integer>> child=new HashMap<>();public LockingTree(int[] parent) {p = parent;for (int i = 0; i < parent.length; i++) {if (!child.containsKey(p[i]))child.put(p[i],new HashSet<>());child.get(p[i]).add(i);}}public boolean lock(int num, int user) {if (locked.containsKey(num) )return false;locked.put(num, user);return true;}public boolean unlock(int num, int user) {if (locked.containsKey(num) && locked.get(num) == user) {locked.remove(num);return true;} else return false;}public boolean dfs(int num) {while (num!=-1){if(locked.containsKey(num))return false;num=p[num];}return true;}public boolean ddfs(int num,int f) {if (locked.containsKey(num)&&num!=f){return true;}boolean res=false;if (child.containsKey(num)){for (Integer integer : child.get(num)) {res|=ddfs(integer,f);}}return res;}public void dddfs(int num) {locked.remove(num);if (child.containsKey(num)){for (Integer integer : child.get(num)) {dddfs(integer);}}}public boolean upgrade(int num, int user) {if (dfs(num)&&ddfs(num,num)){dddfs(num);locked.put(num, user);return true;}return false;}}/*** Your LockingTree object will be instantiated and called as such:* LockingTree obj = new LockingTree(parent);* boolean param_1 = obj.lock(num,user);* boolean param_2 = obj.unlock(num,user);* boolean param_3 = obj.upgrade(num,user);*//*** Your LockingTree object will be instantiated and called as such:* LockingTree obj = new LockingTree(parent);* boolean param_1 = obj.lock(num,user);* boolean param_2 = obj.unlock(num,user);* boolean param_3 = obj.upgrade(num,user);*/

5848. 树上的操作相关推荐

  1. 【线段树】区间修改(区间覆盖、区间权值加)标记下放操作的逻辑顺序

    洛谷传送门:月下"毛景树" 由于没有合适的题目,就从这道题入手,解此题时用到的算法/数据结构包括: 树链剖分 线段树(区间覆盖.区间加.区间查询.单点修改) 这道题被我调试了四个小 ...

  2. [loj6208]树上询问——线段树

    题目大意: 有一棵 n n n节点的树,根为 1" role="presentation">111 号节点.每个节点有两个权值 ki,ti k i , t i k_ ...

  3. 二叉搜索树及其操作详解

    文章目录 二叉搜索树的定义 二叉搜索树的结构特点 二叉搜索树查询 查找 最大关键字元素和最小关键字元素 后继和前驱 二叉搜索树插入和删除 插入 删除 参考<算法导论(第三版)>第 12 章 ...

  4. 树链剖分(维护树上信息)

    学习前请先掌握线段树:线段树(维护区间信息) 一,思想: 将一颗树拆成多条线性链以方便维护(如线段树). 先给出以下定义(通过这些定义我们就可以组成链): 重儿子:子节点最多的儿子就是重儿子 轻儿子: ...

  5. Beautiful Subarrays (01字典树 瞎搞)

    题意: 题解: 一看问的是子序列,并且还是异或. 首先想到01字典树,再一看让你求子序列的个数,大致是想让你把这个序列进行前缀异或处理后然后再01字典树上进行操作吧. 假设01字典树往左边是0右边是1 ...

  6. SP10628 COT - Count on a tree (树剖+可持久化线段树)

    题意: 给定一个包含 N 个结点的树. 树节点从 1 到 N编号..每个节点有一个整数权值. 我们会要求您执行以下操作: u v k : 询问从节点 u 到 节点 v 的路径上的第k小的权值 输入 在 ...

  7. 树链剖分(轻重链剖分) 讲解 (模板题目 P3384 【模板】轻重链剖分 )

    P3384 [模板]轻重链剖分 首先先说一下基本概念: 1.重儿子:一个结点的所有儿子中,大小最大的那个(最重的,所以说只有一个,如果有多个儿子的大小相等那就随便取一个). 2.轻儿子:一个结点的儿子 ...

  8. 人人都是 DBA(VII)B 树和 B+ 树

    B 树(B-Tree)是为磁盘等辅助存取设备设计的一种平衡查找树,它实现了以 O(log n) 时间复杂度执行查找.顺序读取.插入和删除操作.由于 B 树和 B 树的变种在降低磁盘 I/O 操作次数方 ...

  9. 算法导论之红黑树的学习

    最近学习了二叉搜索树中的红黑树,感觉收获颇丰,在此写一篇文章小结一下学到的知识,顺便手写一下Java代码. 1.引言 先来讲讲什么是二叉搜索树,二叉搜索树有如下特点:他是以一颗二叉树(最多有两个子结点 ...

最新文章

  1. 手把手教你使用Flask轻松部署机器学习模型(附代码链接) | CSDN博文精选
  2. Flutter Web:Shadow Root问题
  3. Redis缓存数据库服务器
  4. twisted系列教程十八–异步操作的并行运行
  5. python把hdf转为tif_命令行记录-python读取hdf图层,转成tif文件
  6. 线程同步之 生产者消费者模型详解
  7. 性能测试知多少---性能需求分析
  8. 转-----EasyCHM制作教程
  9. matlab中blur函数_matlab-----均值滤波函数的实现
  10. opencv双目测距
  11. 影之刃服务器维护,影之刃无法联机到服务器怎么办 解决办法
  12. python namedtuple默认值_python 使用 namedtuple
  13. c语言中fl,用C语言操作SPMC75内部FLSASH.doc
  14. Adnroid 自定义流式布局
  15. 中国土地市场网-js解密
  16. 看雪论坛 android,[分享] KSMA -- Android 通用 Root 技术
  17. 计算机二级考试试题c语言,2014年计算机二级c考试试题 1
  18. 电路的耦合方式 直接耦合、阻容耦合、变压器耦合 光电耦合。
  19. 常州SEO姜东:技术搜索引擎优化
  20. 利用百度地图,实现移动端附近门店功能

热门文章

  1. 线程间通信之eventfd
  2. 进程控制块PCB(进程描述符)
  3. Ubuntu下mongodb的安装与配置
  4. WinPcap笔记(3):获取已安装设备的详细信息
  5. virtualbox 使用
  6. [UE4]删除UI:Remove from Parent
  7. 【LeetCode】19. Remove Nth Node From End of List
  8. ESFramework介绍之(23)―― AgileTcp
  9. 封装绑定以BaseDataList , ListControl 为基类的函数库
  10. POJ - 3257 Cow Roller Coaster (背包)