Accepted C# Solution with Union-Find
\n    public class Solution\n    {\n        private static readonly (int di, int dj)[] _directions = { (0, 1), (0, -1), (1, 0), (-1, 0) };\n\n        private cl
```\n    public class Solution\n    {\n        private static readonly (int di, int dj)[] _directions = { (0, 1), (0, -1), (1, 0), (-1, 0) };\n\n        private class Unions\n        {\n            private readonly int[] _parents;\n            private readonly int[] _ranks;\n\n            public Unions(int n)\n            {\n                _parents = new int[n];\n                _ranks = new int[n];\n                for (int i = 0; i < n; i++)\n                {\n                    _parents[i] = i;\n                }\n            }\n\n            public int Find(int x)\n            {\n                if (x != _parents[x])\n                {\n                    x = Find(_parents[x]);\n                }\n                return _parents[x];\n            }\n\n            public bool Union(int x, int y)\n            {\n                int px = Find(x);\n                int py = Find(y);\n                if (px == py)\n                {\n                    return false;\n                }\n                if (_ranks[px] > _ranks[py])\n                {\n                    _parents[py] = px;\n                    _ranks[px]++;\n                }\n                else\n                {\n                    _parents[px] = py;\n                    _ranks[py]++;\n                }\n                return true;\n            }\n        }\n\n        public int ContainVirus(int[][] grid)\n        {\n            int n = grid.Length;\n            int m = grid[0].Length;\n\n            int res = 0;\n            while (true)\n            {\n                Unions dsu = new Unions(n * m);\n\n                for (int i = 0; i < n; i++)\n                {\n                    for (int j = 0; j < m; j++)\n                    {\n                        int linear = i * m + j;\n\n                        if (grid[i][j] == 1)\n                        {\n                            foreach (var dir in _directions)\n                            {\n                                int newI = i + dir.di;\n                                int newJ = j + dir.dj;\n\n                                if (newI >= 0 && newI < n && newJ >= 0 && newJ < m && grid[newI][newJ] == 1)\n                                {\n                                    dsu.Union(linear, newI * m + newJ);\n                                }\n                            }\n                        }\n                    }\n                }\n\n                IDictionary<int, ISet<int>> root2Cells = new Dictionary<int, ISet<int>>();\n\n                for (int i = 0; i < n; i++)\n                {\n                    for (int j = 0; j < m; j++)\n                    {\n                        if (grid[i][j] == 1)\n                        {\n                            var root = dsu.Find(i * m + j);\n                            if (!root2Cells.ContainsKey(root))\n                            {\n                                root2Cells[root] = new HashSet<int>();\n                            }\n\n                            root2Cells[root].Add(i * m + j);\n                        }\n                    }\n                }\n\n\n                IList<(ISet<int> set, int root)> nextCellCollections =\n                    new List<(ISet<int> set, int root)>(root2Cells.Count);\n\n                foreach (var r2c in root2Cells)\n                {\n                    ISet<int> next = new HashSet<int>();\n\n                    foreach (var lidx in r2c.Value)\n                    {\n                        int i = lidx / m;\n                        int j = lidx % m;\n\n                        foreach (var dir in _directions)\n                        {\n                            int newI = i + dir.di;\n                            int newJ = j + dir.dj;\n\n                            if (newI >= 0 && newI < n && newJ >= 0 && newJ < m && (grid[newI][newJ] == 0 || grid[newI][newJ] == 2))\n                            {\n                                next.Add(newI * m + newJ);\n                                grid[newI][newJ] = 2;\n                            }\n                        }\n                    }\n\n                    nextCellCollections.Add((next, r2c.Key));\n                }\n\n                if (nextCellCollections.Count == 0)\n                {\n                    break;\n                }\n\n                (ISet<int> set, int root)? max = null;\n                foreach (var cand in nextCellCollections)\n                {\n                    max = max ?? cand;\n                    if (cand.set.Count > max.Value.set.Count)\n                    {\n                        max = cand;\n                    }\n                }\n\n\n                foreach (var lidx in max.Value.set)\n                {\n                    int i = lidx / m;\n                    int j = lidx % m;\n\n                    foreach (var dir in _directions)\n                    {\n                        int newI = i + dir.di;\n                        int newJ = j + dir.dj;\n\n                        if (newI >= 0 && newI < n && newJ >= 0 && newJ < m && grid[newI][newJ] == 1)\n                        {\n                            if (dsu.Find(newI * m + newJ) == max.Value.root)\n                            {\n                                res++;\n                            }\n                        }\n                    }\n                }\n\n\n                foreach (var lidx in root2Cells[max.Value.root])\n                {\n                    int i = lidx / m;\n                    int j = lidx % m;\n                    grid[i][j] = 3;\n                }\n\n\n                nextCellCollections.Remove(max.Value);\n                for (int collectionIdx = 0; collectionIdx < nextCellCollections.Count; collectionIdx++)\n                {\n                    var cells = nextCellCollections[collectionIdx];\n\n                    foreach (var lidx in cells.set)\n                    {\n                        int i = lidx / m;\n                        int j = lidx % m;\n\n                        grid[i][j] = 1;\n                    }\n                }\n                 \n                if (nextCellCollections.Count == 0)\n                {\n                    break;\n                }\n            }\n\n            return res;\n        }\n    }\n```
['Union Find']