diff --git a/leetcode/1901-2000/1993.Operations-on-Tree/README.md b/leetcode/1901-2000/1993.Operations-on-Tree/README.md index 94d4edbde..a878029e3 100755 --- a/leetcode/1901-2000/1993.Operations-on-Tree/README.md +++ b/leetcode/1901-2000/1993.Operations-on-Tree/README.md @@ -1,28 +1,49 @@ # [1993.Operations on Tree][title] -> [!WARNING|style:flat] -> This question is temporarily unanswered if you have good ideas. Welcome to [Create Pull Request PR](https://github.com/kylesliu/awesome-golang-algorithm) - ## Description +You are given a tree with `n` nodes numbered from `0` to `n - 1` in the form of a parent array `parent` where `parent[i]` is the parent of the ith node. The root of the tree is node `0`, so `parent[0] = -1` since it has no parent. You want to design a data structure that allows users to lock, unlock, and upgrade nodes in the tree. -**Example 1:** +The data structure should support the following functions: -``` -Input: a = "11", b = "1" -Output: "100" -``` +- **Lock: Locks** the given node for the given user and prevents other users from locking the same node. You may only lock a node using this function if the node is unlocked. +- **Unlock: Unlocks** the given node for the given user. You may only unlock a node using this function if it is currently locked by the same user. +- **Upgrade: Locks** the given node for the given user and **unlocks** all of its descendants **regardless** of who locked it. You may only upgrade a node if **all** 3 conditions are true: -## 题意 -> ... + - The node is unlocked, + - It has at least one locked descendant (by any user), and + - It does not have any locked ancestors. -## 题解 +Implement the `LockingTree` class: -### 思路1 -> ... -Operations on Tree -```go -``` +- `LockingTree(int[] parent)` initializes the data structure with the parent array. +- `lock(int num, int user)` returns `true` if it is possible for the `user` with id user to lock the node `num`, or false otherwise. If it is possible, the node `num` will become **locked** by the user with id `user`. +- `unlock(int num, int user)` returns `true` if it is possible for the `user` with id user to unlock the node `num`, or `false` otherwise. If it is possible, the node `num` will become **unlocked**. +- `upgrade(int num, int user)` returns `true` if it is possible for the `user` with id user to upgrade the node `num`, or `false` otherwise. If it is possible, the node `num` will be **upgraded**. +**Example 1:** + +![1](./untitled.png) + +``` +Input +["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]] +Output +[null, true, false, true, true, true, false] + +Explanation +LockingTree lockingTree = new LockingTree([-1, 0, 0, 1, 1, 2, 2]); +lockingTree.lock(2, 2); // return true because node 2 is unlocked. + // Node 2 will now be locked by user 2. +lockingTree.unlock(2, 3); // return false because user 3 cannot unlock a node locked by user 2. +lockingTree.unlock(2, 2); // return true because node 2 was previously locked by user 2. + // Node 2 will now be unlocked. +lockingTree.lock(4, 5); // return true because node 4 is unlocked. + // Node 4 will now be locked by user 5. +lockingTree.upgrade(0, 1); // return true because node 0 is unlocked and has at least one locked descendant (node 4). + // Node 0 will now be locked by user 1 and node 4 will now be unlocked. +lockingTree.lock(0, 1); // return false because node 0 is already locked. +``` ## 结语 diff --git a/leetcode/1901-2000/1993.Operations-on-Tree/Solution.go b/leetcode/1901-2000/1993.Operations-on-Tree/Solution.go index d115ccf5e..2e52ab703 100644 --- a/leetcode/1901-2000/1993.Operations-on-Tree/Solution.go +++ b/leetcode/1901-2000/1993.Operations-on-Tree/Solution.go @@ -1,5 +1,102 @@ package Solution -func Solution(x bool) bool { - return x +type LockingTree struct { + tree []int + locker []int + children map[int][]int +} + +func Constructor(parent []int) LockingTree { + children := make(map[int][]int) + for c, p := range parent { + if _, ok := children[p]; !ok { + children[p] = make([]int, 0) + } + children[p] = append(children[p], c) + } + return LockingTree{tree: parent, locker: make([]int, len(parent)), children: children} +} + +// u, u, ul, l, u +func (this *LockingTree) Lock(num int, user int) bool { + if this.locker[num] != 0 { + return false + } + this.locker[num] = user + return true +} + +func (this *LockingTree) Unlock(num int, user int) bool { + if this.locker[num] == 0 || this.locker[num] != user { + return false + } + this.locker[num] = 0 + return true +} + +func (this *LockingTree) ancesors(num int) bool { + for { + if num == -1 { + return false + } + if this.locker[num] != 0 { + return true + } + num = this.tree[num] + } +} + +func (this *LockingTree) unlockDescendant(num int) bool { + q := []int{num} + found := false + for len(q) > 0 { + nq := make([]int, 0) + for _, i := range q { + if this.locker[i] != 0 { + this.locker[i] = 0 + found = true + } + for _, c := range this.children[i] { + nq = append(nq, c) + } + } + q = nq + } + return found +} + +func (this *LockingTree) Upgrade(num int, user int) bool { + if this.locker[num] != 0 { + return false + } + if this.ancesors(num) { + return false + } + if !this.unlockDescendant(num) { + return false + } + this.locker[num] = user + return true +} + +type op struct { + name string + a, b int +} + +func Solution(p []int, opts []op) []bool { + c := Constructor(p) + ans := make([]bool, 0) + for _, o := range opts { + if o.name == "l" { + ans = append(ans, c.Lock(o.a, o.b)) + continue + } + if o.name == "u" { + ans = append(ans, c.Unlock(o.a, o.b)) + continue + } + ans = append(ans, c.Upgrade(o.a, o.b)) + } + return ans } diff --git a/leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go b/leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go index 14ff50eb4..ed018fe28 100644 --- a/leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go +++ b/leetcode/1901-2000/1993.Operations-on-Tree/Solution_test.go @@ -10,30 +10,36 @@ func TestSolution(t *testing.T) { // 测试用例 cases := []struct { name string - inputs bool - expect bool + p []int + opts []op + expect []bool }{ - {"TestCase", true, true}, - {"TestCase", true, true}, - {"TestCase", false, false}, + {"TestCase1", []int{-1, 0, 0, 1, 1, 2, 2}, []op{ + {"l", 2, 2}, + {"u", 2, 3}, + {"u", 2, 2}, + {"l", 4, 5}, + {"", 0, 1}, + {"l", 0, 1}, + }, []bool{true, false, true, true, true, false}}, } // 开始测试 for i, c := range cases { t.Run(c.name+" "+strconv.Itoa(i), func(t *testing.T) { - got := Solution(c.inputs) + got := Solution(c.p, c.opts) if !reflect.DeepEqual(got, c.expect) { - t.Fatalf("expected: %v, but got: %v, with inputs: %v", - c.expect, got, c.inputs) + t.Fatalf("expected: %v, but got: %v, with inputs: %v %v", + c.expect, got, c.p, c.opts) } }) } } -// 压力测试 +// 压力测试 func BenchmarkSolution(b *testing.B) { } -// 使用案列 +// 使用案列 func ExampleSolution() { } diff --git a/leetcode/1901-2000/1993.Operations-on-Tree/untitled.png b/leetcode/1901-2000/1993.Operations-on-Tree/untitled.png new file mode 100644 index 000000000..6666b1e9f Binary files /dev/null and b/leetcode/1901-2000/1993.Operations-on-Tree/untitled.png differ