Notes

The best way I've seen to code this kind of DSU, is style of bmerry : (C++)

initially are parents are set to -1

for each root v, 
  par[v] equals the negative of number of tools in that box.

source: Algorithm Gym :: Data structures by DarthKnight https://codeforces.com/blog/entry/15729

vector<int> par = vector<int>(n, -1);

int root(int v){return par[v] < 0 ? v : (par[v] = root(par[v]));}

void merge(int x,int y){    //  x and y are some tools (vertices)
    if((x = root(x)) == (y = root(y)))  return;
    if(par[y] < par[x]) // balancing the height of the tree
        swap(x, y);
    par[x] += par[y];
    par[y] = x;
}

source: kmjp https://kmjp.hatenablog.jp/entry/2020/06/18/0900 https://codeforces.com/contest/1278/submission/67749296

template<int um> class UF {
    public:
    vector<int> par,rank,cnt;
    UF() {par=rank=vector<int>(um,0); cnt=vector<int>(um,1); for(int i=0;i<um;i++) par[i]=i;}
    void reinit() {for(int i=0;i<um;i++) rank[i]=0,cnt[i]=1,par[i]=i;}
    int operator[](int x) {return (par[x]==x)?(x):(par[x] = operator[](par[x]));}
    int count(int x) { return cnt[operator[](x)];}
    int operator()(int x,int y) {
        if((x=operator[](x))==(y=operator[](y))) return x;
        cnt[y]=cnt[x]=cnt[x]+cnt[y];
        if(rank[x]>rank[y]) return par[x]=y;
        rank[x]+=rank[x]==rank[y]; return par[y]=x;
    }
};
UF<500000> uf;

Can directly use uf[y]==uf[x] to check whether both are in same union and uf(y,x); to combine both of them

struct UnionFind{
  int num;
  vector<int> rs,ps;
  UnionFind(int n):num(n),rs(n,1),ps(n,0){
    iota(ps.begin(),ps.end(),0);
  }
  int find(int x){
    return (x==ps[x]?x:ps[x]=find(ps[x]));
  }
  bool same(int x,int y){
    return find(x)==find(y);
  }
  void unite(int x,int y){
    x=find(x);y=find(y);
    if(x==y) return;
    if(rs[x]<rs[y]) swap(x,y);
    rs[x]+=rs[y];
    ps[y]=x;
    num--;
  }
  int size(int x){
    return rs[find(x)];
  }
  int count() const{
    return num;
  }
};

source: User:beet https://atcoder.jp/contests/zone2021/submissions/22207964

Benq's implementation

struct DSU {
	vector<int> e; void init(int N) { e = vector<int>(N,-1); }
	int get(int x) { return e[x] < 0 ? x : e[x] = get(e[x]); }
	bool sameSet(int a, int b) { return get(a) == get(b); }
	int size(int x) { return -e[get(x)]; }
	bool unite(int x, int y) { // union by size
		x = get(x), y = get(y); if (x == y) return 0;
		if (e[x] > e[y]) swap(x,y);
		e[x] += e[y]; e[y] = x; return 1;
	}
};
	   
// Usage
DSU D;
int n,m;
vector<int> comps;

void init() {
	cin >> n >> m; D.init(n);
	for (int i = 0; i < m; ++i) {
		int a,b; cin >> a >> b;
		D.unite(a-1,b-1);
	}
	for (int i = 0; i < n; ++i) if (D.get(i) == i)
		comps.push_back(D.size(i));
}

source: https://usaco.guide/plat/bitsets?lang=cpp

Union Find Data Structure Application

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.

class Solution(object):
    def friendRequests(self, n, restrictions, requests):
        """
        :type n: int
        :type restrictions: List[List[int]]
        :type requests: List[List[int]]
        :rtype: List[bool]
        """
        ufp = [-1] * n
        ufr = [0] * n

        def _find(u):
            p = []
            while ufp[u] >= 0:
                p.append(u)
                u = ufp[u]
            for v in p:
                ufp[v] = u
            return u

        def _union(u, v):
            u = _find(u)
            v = _find(v)
            if u == v:
                return
            if ufr[u] < ufr[v]:
                u, v = v, u
            ufp[v] = u
            if ufr[u] == ufr[v]:
                ufr[u] += 1

        def _check(u, v):
            u = _find(u)
            v = _find(v)
            if u == v:
                return True
            for x, y in restrictions:
                x = _find(x)
                y = _find(y)
                assert x != y
                if x == u and y == v:
                    return False
                if x == v and y == u:
                    return False
            return True

        r = []
        for u, v in requests:
            u = _find(u)
            v = _find(v)
            if _check(u, v):
                r.append(True)
                _union(u, v)
            else:
                r.append(False)
        return r

LeetCode - Subarray With Elements Greater Than Varying Threshold

You are given an integer array nums and an integer threshold.

Find any subarray of nums of length k such that every element in the subarray is greater than threshold / k.

Return the size of any such subarray. If there is no such subarray, return -1.

class Solution {
public:
    vector<int> par;

    int root(int v) {return par[v] < 0 ? v : (par[v] = root(par[v]));}

    void merge(int x,int y){    //  x and y are some tools (vertices)
        if((x = root(x)) == (y = root(y)))  return;
        if(par[y] < par[x]) // balancing the height of the tree
            swap(x, y);
        par[x] += par[y];
        par[y] = x;
    }
    
    int validSubarraySize(vector<int>& nums, int threshold) {
        par  = vector<int>(nums.size(), -1);
        vector<pair<int, int>> V;
        for(int i=0;i<nums.size();i++) V.push_back({nums[i], i});
        sort(V.rbegin(), V.rend());
        for(pair<int, int> x: V){
            int i = x.second;
            int min_element_of_group = x.first;
            if(i > 0 && nums[i-1] >= nums[i]) merge(i-1, i);
            if(i + 1 < nums.size() && nums[i+1] >= nums[i]) merge(i, i+1);
            int size_of_group = -par[root(i)];
            if(min_element_of_group*size_of_group > threshold){
                return size_of_group;
            }
        }
        return -1;
    }
};