You are given an integer n indicating the number of people in a network. Each person is labeled from 0 to n - 1.

You are also given a 0-indexed 2D integer array restrictions, where restrictions[i] = [xi, yi] means that person xi and person yi cannot become friends, either directly or indirectly through other people.

Initially, no one is friends with each other. You are given a list of friend requests as a 0-indexed 2D integer array requests, where requests[j] = [uj, vj] is a friend request between person uj and person vj.

A friend request is successful if uj and vj can be friends. Each friend request is processed in the given order (i.e., requests[j] occurs before requests[j + 1]), and upon a successful request, uj and vj become direct friends for all future friend requests.

Return a boolean array result, where each result[j] is true if the jth friend request is successful or false if it is not.

Note: If uj and vj are already direct friends, the request is still successful.

&nbsp;
Example 1:

Input: n = 3, restrictions = [[0,1]], requests = [[0,2],[2,1]]
Output: [true,false]
Explanation:
Request 0: Person 0 and person 2 can be friends, so they become direct friends. 
Request 1: Person 2 and person 1 cannot be friends since person 0 and person 1 would be indirect friends (1--2--0).


Example 2:

Input: n = 3, restrictions = [[0,1]], requests = [[1,2],[0,2]]
Output: [true,false]
Explanation:
Request 0: Person 1 and person 2 can be friends, so they become direct friends.
Request 1: Person 0 and person 2 cannot be friends since person 0 and person 1 would be indirect friends (0--2--1).


Example 3:

Input: n = 5, restrictions = [[0,1],[1,2],[2,3]], requests = [[0,4],[1,2],[3,1],[3,4]]
Output: [true,false,true,false]
Explanation:
Request 0: Person 0 and person 4 can be friends, so they become direct friends.
Request 1: Person 1 and person 2 cannot be friends since they are directly restricted.
Request 2: Person 3 and person 1 can be friends, so they become direct friends.
Request 3: Person 3 and person 4 cannot be friends since person 0 and person 1 would be indirect friends (0--4--3--1).


&nbsp;
Constraints:


	2 &lt;= n &lt;= 1000
	0 &lt;= restrictions.length &lt;= 1000
	restrictions[i].length == 2
	0 &lt;= xi, yi &lt;= n - 1
	xi != yi
	1 &lt;= requests.length &lt;= 1000
	requests[j].length == 2
	0 &lt;= uj, vj &lt;= n - 1
	uj != vj


class UnionFindSet(object):
    def __init__(self, n):
        self.data = range(n)

    def find(self, x):
        while x <> self.data[x]:
            x = self.data[x]
        return x

    def union(self, x, y):
        self.data[self.find(x)] = self.find(y)

    def speedup(self):
        for i in range(len(self.data)):
            self.data[i] = self.find(i)


class Solution(object):
    def friendRequests(self, n, restrictions, requests):
        uf = UnionFindSet(n)
        ret = [True] * len(requests)
        for k, [x, y] in enumerate(requests):  # Process Requests Sequentially
            xh = uf.find(x)  # backup the head of x for undo
            uf.union(x, y)  # link [x, y] and verify if any restriction triggers
            for [i, j] in restrictions:
                if uf.find(i) == uf.find(j):
                    ret[k] = False
                    break
            if not ret[k]:  # if any restriction triggers, undo
                uf.data[xh] = xh
            else:
                uf.speedup()
        return ret
class Solution {
    int[] parent;
    boolean[] result;
    
    public boolean[] friendRequests(int n, int[][] restrictions, int[][] requests) {
        parent = new int[n];
        for (int i = 0; i < n; i++) {
            parent[i] = i;
        }
        result = new boolean[requests.length];
        
        for (int i = 0; i < requests.length; i++) {
            // personA and personB can become friends if for all restrictions
            // person x_i and person y_i are not in the same set as personA and personB
            // and vice versa
            int personA = requests[i][0];
            int personB = requests[i][1];
            int personASetRepresentative = find(personA);
            int personBSetRepresentative = find(personB);
            boolean flag = true;
            for (int[] restriction : restrictions) {
                int blackListPersonARepresentative = find(restriction[0]);
                int blackListPersonBRepresentative = find(restriction[1]);
                if (personASetRepresentative == blackListPersonARepresentative && personBSetRepresentative == blackListPersonBRepresentative) {
                    flag = false;
                }
                if (personASetRepresentative == blackListPersonBRepresentative && personBSetRepresentative == blackListPersonARepresentative) {
                    flag = false;
                }
            }
            if (flag) {
                union(personA, personB);
            }
            result[i] = flag;
        }
        return result;
    }
    
    private int find(int node) {
        int root = node;
        while (parent[root] != root) {
            root = parent[root];
        }
        
        //path compression
        int curr = node;
        while (parent[curr] != root) {
            int next = parent[curr];
            parent[curr] = root;
            curr = next;
        }
        return root;
    }
    
    private boolean union(int node1, int node2) {
        int root1 = find(node1);
        int root2 = find(node2);
        if (root1 == root2) {
            return false;
        }
        parent[root2] = root1;
        return true;
    }
}
/ Standard DSU Class
class DSU {
    vector<int> parent, size;
public:

    DSU(int n) {
        for(int i=0; i<=n; i++) {
            parent.push_back(i);
            size.push_back(1);
        }
    }

    int findParent(int num) {
        if(parent[num] == num) return num;
        return parent[num] = findParent(parent[num]);
    }

    // Directly getting parents of u and v
    // To avoid finding parent multiple times
    void unionBySize(int parU, int parV) {

        if(size[parU] < size[parV]) {
            size[parV] += size[parU];
            parent[parU] = parV;
        }
        else {
            size[parU] += size[parV];
            parent[parV] = parU;
        }
    }
};

class Solution {
public:
    vector<bool> friendRequests(int n, vector<vector<int>>& restrictions, vector<vector<int>>& requests) {

        DSU dsu(n);

        vector<bool> successful;

        for(auto& request : requests) {

            int u = request[0], v = request[1];

            int parU = dsu.findParent(u), parV = dsu.findParent(v);

            bool flag = true;

            if(parU != parV) {

                // Check if current friend requested is restricted or not.
                for(auto& restriction : restrictions) {
                    int restricted_U = restriction[0], restricted_V = restriction[1];

                    int restricted_parU = dsu.findParent(restricted_U);
                    int restricted_parV = dsu.findParent(restricted_V);

                    if((parU == restricted_parU && parV == restricted_parV) || (parU == restricted_parV && parV == restricted_parU)) {
                        flag = false;
                        break;
                    }
                }

                // Union u and v by passing parents
                // Since it is already calculated above
                if(flag) {
                    dsu.unionBySize(parU, parV);
                }
            }

            successful.push_back(flag);
        }

        return successful;
    }
};
/*
DSU Class Template
*/
class DSU {
    constructor() {
        this.parents = new Map();
        this.rank = new Map();
    }

    add(x) {
        this.parents.set(x, x);
        this.rank.set(x, 0);
    }

    find(x) {
        const parent = this.parents.get(x);
        if (parent === x) return x;
        const setParent = this.find(parent);
        this.parents.set(x, setParent);
        return setParent;
    }

    union(x, y) {
        const xParent = this.find(x), yParent = this.find(y);
        const xRank = this.rank.get(xParent), yRank = this.rank.get(yParent);
        if (xParent === yParent) return;
        if (xRank > yRank) {
            this.parents.set(yParent, xParent);
        } else if (yRank > xRank) {
            this.parents.set(xParent, yParent);
        } else {
            this.parents.set(xParent, yParent);
            this.rank.set(yParent, yRank + 1);
        }
    }
}

/*
Friend Requests
*/
var friendRequests = function(n, restrictions, requests) {
    const dsu = new DSU(), result = [];
    for (let i = 0; i < n; i++) dsu.add(i);

    for (let [friend1, friend2] of requests) {
        const parent1 = dsu.find(friend1), parent2 = dsu.find(friend2);
        let friendshipPossible = true;
        for (let [enemy1, enemy2] of restrictions) {
            const enemyParent1 = dsu.find(enemy1), enemyParent2 = dsu.find(enemy2);
            const condition1 = (enemyParent1 === parent1 && enemyParent2 === parent2);
            const condition2 = (enemyParent1 === parent2 && enemyParent2 === parent1);
            if (condition1 || condition2) {
                friendshipPossible = false;
                break;
            }
        }
        if (friendshipPossible) dsu.union(friend1, friend2);
        result.push(friendshipPossible);
    }
    return result;
};
Process Restricted Friend Requests