Union Find
Complexity

# Complexity
<!-- Add your time complexity here, e.g. $$O(n)$$ -->
```python3 []
class UnionFind:
    def __init__(self, n, restrictions):
        self.n = n
        self.parent = [i for i in range(n)]
        self.rank = [0] * n
        self.restrictions = defaultdict(list)

        for x, y in restrictions:
            self.restrictions[x].append(y)
            self.restrictions[y].append(x)

    
    def find(self, i):
        if self.parent[i] != i:
            self.parent[i] = self.find(self.parent[i])
        return self.parent[i]
    
    def union(self, i, j):
        i = self.find(i)
        j = self.find(j)

        # update the parents
        for x in range(self.n):
            self.find(x)

        # check for each of the nodes in the same set as i
        # if any of the restrictions of that node are in j
        # symmetrical so only need to run once
        for x in range(self.n):
            if self.parent[x] == i:
                for k in self.restrictions[x]:
                    if self.find(k) == j:
                        return False

        if i == j:
            return True
        
        if self.rank[i] > self.rank[j]:
            self.parent[j] = i
        elif self.rank[i] < self.rank[j]:
            self.parent[i] = j
        else:
            self.parent[i] = j
            self.rank[j] += 1
        return True


class Solution:
    def friendRequests(self, n: int, restrictions: List[List[int]], requests: List[List[int]]) -> List[bool]:
        dsu = UnionFind(n, restrictions)
        ans = []

        for x, y in requests:
            ans.append(dsu.union(x,y))

        return ans
```
['Python3']