1993. 树上的操作
给你一棵 n 个节点的树,编号从 0 到 n - 1 ,以父节点数组 parent 的形式给出,其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点,所以 parent[0] = -1 ,因为它没有父节点。你想要设计一个数据结构实现树里面对节点的加锁,解锁和升级操作。
数据结构需要支持如下函数:
Lock:指定用户给指定节点 上锁 ,上锁后其他用户将无法给同一节点上锁。只有当节点处于未上锁的状态下,才能进行上锁操作。
Unlock:指定用户给指定节点 解锁 ,只有当指定节点当前正被指定用户锁住时,才能执行该解锁操作。
Upgrade:指定用户给指定节点 上锁 ,并且将该节点的所有子孙节点 解锁 。只有如下 3 个条件 全部 满足时才能执行升级操作:
LockingTree(int[] parent) 用父节点数组初始化数据结构。
l- ock(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 会被 升级 。
class LockingTree {
public:
LockingTree(vector<int>& parent) {
int n = parent.size();
this->parent = parent;
this->lockNodeUser = vector<int>(n, -1);
this->children = vector<vector<int>>(n);
for (int i = 0; i < n; i++) {
int p = parent[i];
if (p != -1) {
children[p].emplace_back(i);
}
}
}
bool lock(int num, int user) {
if (lockNodeUser[num] == -1) {
lockNodeUser[num] = user;
return true;
}
return false;
}
bool unlock(int num, int user) {
if (lockNodeUser[num] == user) {
lockNodeUser[num] = -1;
return true;
}
return false;
}
bool upgrade(int num, int user) {
bool res = lockNodeUser[num] == -1 \
&& !hasLockedAncestor(num) \
&& checkAndUnlockDescendant(num);
if (res) {
lockNodeUser[num] = user;
}
return res;
}
bool hasLockedAncestor(int num) {
num = parent[num];
while (num != -1) {
if (lockNodeUser[num] != -1) {
return true;
}
num = parent[num];
}
return false;
}
bool checkAndUnlockDescendant(int num) {
bool res = lockNodeUser[num] != -1;
lockNodeUser[num] = -1;
for (int child : children[num]) {
res |= checkAndUnlockDescendant(child);
}
return res;
}
private:
vector<int> parent;
vector<int> lockNodeUser;
vector<vector<int>> children;
};
(1) 采用深度优先搜索的思想。