Problem:

Score : 300 points

Problem Statement

There are N cities on a 2D plane. The coordinate of the i-th city is (x_i, y_i). Here (x_1, x_2, \dots, x_N) and (y_1, y_2, \dots, y_N) are both permuations of (1, 2, \dots, N).

For each k = 1,2,\dots,N, find the answer to the following question:

Rng is in City k.
Rng can perform the following move arbitrarily many times:

move to another city that has a smaller x-coordinate and a smaller y-coordinate, or a larger x-coordinate and a larger y-coordinate, than the city he is currently in.

How many cities (including City k) are reachable from City k?

Constraints

1 \leq N \leq 200,000

(x_1, x_2, \dots, x_N) is a permutation of (1, 2, \dots, N).

(y_1, y_2, \dots, y_N) is a permutation of (1, 2, \dots, N).

All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
x_1 y_1
x_2 y_2
:
x_N y_N

Output

Print N lines. In i-th line print the answer to the question when k = i.

Sample Input 1

4
1 4
2 3
3 1
4 2

Sample Output 1

1
1
2
2

Rng can reach City 4 from City 3, or conversely City 3 from City 4.

Sample Input 2

7
6 4
4 3
3 5
7 1
2 7
5 2
1 6

Sample Output 2

3
3
1
1
2
3
2



Sample input:
4
1 4
2 3
3 1
4 2


Sample output:
1
1
2
2

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

def I(): return int(input())
def MI(): return map(int, input().split())
def LI(): return list(map(int, input().split()))

def main():
    class Segtree:
        def __init__(self, A, ide_ele, initialize = True, segf = max):
            self.N = len(A)
            self.N0 = 2**(self.N-1).bit_length()
            self.ide_ele = ide_ele
            self.segf = segf
            if initialize:
                self.data = [ide_ele]*self.N0 + A + [ide_ele]*(self.N0 - self.N)
                for i in range(self.N0-1, 0, -1):
                    self.data[i] = self.segf(self.data[2*i], self.data[2*i+1]) 
            else:
                self.data = [ide_ele]*(2*self.N0)

        def update(self, k, x):
            k += self.N0
            self.data[k] = x
            while k > 0 :
                k = k >> 1
                self.data[k] = self.segf(self.data[2*k], self.data[2*k+1])

        def query(self, l, r):
            L, R = l+self.N0, r+self.N0
            s = self.ide_ele
            t = self.ide_ele
            while L < R:
                if L & 1:
                    s = self.segf(s,self.data[L])
                    L += 1
                if R & 1:
                    R -= 1
                    t = self.segf(self.data[R],t)
                L >>= 1
                R >>= 1
            return self.segf(s,t)

        # セグ木上で二分探索，[l,r)の範囲でcheck関数を満たす最小の値をとるところのindexを返す．
        # reverse=Trueなら最大値かな
        # ない時の返り値がNoneなことに注意
        def binsearch(self, l, r, check, reverse = False):
            L, R = l+self.N0, r+self.N0
            SL, SR = [], []
            while L < R:
                if R & 1:
                    R -= 1
                    SR.append(R)
                if L & 1:
                    SL.append(L)
                    L += 1
                L >>= 1
                R >>= 1

            if reverse:
                pre = self.ide_ele
                for idx in (SR + SL[::-1]):
                    if check(self.segf(self.data[idx], pre)):
                        break
                    else:
                        pre = self.segf(self.data[idx], pre)
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(self.data[2*idx+1], pre)):
                        idx = 2*idx + 1
                    else:
                        pre = self.segf(self.data[2*idx+1], pre)
                        idx = 2*idx
                return idx - self.N0
            else:
                pre = self.ide_ele
                for idx in (SL + SR[::-1]):
                    if not check(self.segf(pre, self.data[idx])):
                        pre = self.segf(pre, self.data[idx])
                    else:
                        break
                else:
                    return None
                while idx < self.N0:
                    if check(self.segf(pre, self.data[2*idx])):
                        idx = 2*idx
                    else:
                        pre = self.segf(pre, self.data[2*idx])
                        idx = 2*idx + 1
                return idx - self.N0

    class UnionFind:
        def __init__(self, N: int):
            """
            N:要素数
            root:各要素の親要素の番号を格納するリスト.
                 ただし, root[x] < 0 ならその頂点が根で-root[x]が木の要素数.
            rank:ランク
            """
            self.N = N
            self.root = [-1] * N
            self.rank = [0] * N

        def __repr__(self):
            return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

        def find(self, x: int):
            """頂点xの根を見つける"""
            if self.root[x] < 0:
                return x
            else:
                while self.root[x] >= 0:
                    x = self.root[x]
                return x

        def union(self, x: int, y: int):
            """x,yが属する木をunion"""
            # 根を比較する
            # すでに同じ木に属していた場合は何もしない.
            # 違う木に属していた場合はrankを見てくっつける方を決める.
            # rankが同じ時はrankを1増やす
            x = self.find(x)
            y = self.find(y)
            if x == y:
                return
            elif self.rank[x] > self.rank[y]:
                self.root[x] += self.root[y]
                self.root[y] = x
            else:
                self.root[y] += self.root[x]
                self.root[x] = y
                if self.rank[x] == self.rank[y]:
                    self.rank[y] += 1

        def same(self, x: int, y: int):
            """xとyが同じグループに属するかどうか"""
            return self.find(x) == self.find(y)

        def count(self, x):
            """頂点xが属する木のサイズを返す"""
            return - self.root[self.find(x)]

        def members(self, x):
            """xが属する木の要素を列挙"""
            _root = self.find(x)
            return [i for i in range(self.N) if self.find == _root]

        def roots(self):
            """森の根を列挙"""
            return [i for i, x in enumerate(self.root) if x < 0]

        def group_count(self):
            """連結成分の数"""
            return len(self.roots())

        def all_group_members(self):
            """{ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す"""
            return {r: self.members(r) for r in self.roots()}
    
    N=I()
    X=[0]*N
    Y=[0]*N
    
    from collections import defaultdict
    dd = defaultdict(int)# y2i
    X2Y = defaultdict(int)
    
    for i in range(N):
        X[i],Y[i]=MI()
        X[i]-=1
        Y[i]-=1
        
        X2Y[X[i]]=Y[i]
        dd[Y[i]]=i
        
    X.sort()
    uf=UnionFind(N)
    
    inf = 10**7
    seg=Segtree([-1]*N,-100,segf=max)
    seg2=Segtree([inf]*N,inf,segf=min)
    
    # xを小さい順に並べておけば既出のものは必ずx座標が小さい．結べるものの中でy座標が最大のものと繋いでおく，最小のものも繋いでおくか
    for i in range(N):
        y=X2Y[X[i]]
        k=dd[y]
        yM=seg.query(0,y)
        kM=dd[yM]  
        if yM>=0:#あれば
            uf.union(k,kM)
            
        ym=seg2.query(0,y)
        km=dd[ym]
        if ym<inf:
            uf.union(k,km)
        
        seg.update(y,y)
        seg2.update(y,y)
        
    # 逆向きに見る
    seg=Segtree([-1]*N,-100,segf=max)
    seg2=Segtree([inf]*N,inf,segf=min)
    for i in range(N-1,-1,-1):
        y=X2Y[X[i]]
        k=dd[y]
        yM=seg.query(y,N)
        kM=dd[yM]  
        if yM>=0:#あれば
            uf.union(k,kM)
            
        ym=seg2.query(y,N)
        km=dd[ym]
        if ym<inf:
            uf.union(k,km)

        seg.update(y,y)
        seg2.update(y,y)
        
    roots=[0]*N
    for i in range(N):
        y=X2Y[X[i]]
        k=dd[y]
        roots[k]=uf.find(k)
        
    ddr = defaultdict(lambda:-1)
        
    for i in range(N):
        root=roots[i]
        if ddr[root]!=-1:
            print(ddr[root])
        else:
            ans=uf.count(root)
            print(ans)
            ddr[root]=ans
        
        
        
    
    

main()

Submission status: Accepted

Solution code:
N, *XY = map(int, open(0).read().split())
X, Y = XY[::2], XY[1::2]
XtoY = [0] * (N+1)
for x, y in zip(X,Y):
  XtoY[x] = y

ans = [0] * (N+1)
l = 1
min_y = N + 1
for x in range(1, N+1):
  min_y = min(min_y, XtoY[x])
  if x + min_y == N+1:
    for i in range(l, x+1):
      ans[i] = x - l + 1
    l, min_y = x+1, N+1

for x in X:
  print(ans[x])

Submission status: Accepted

Solution code:
def main():
    examA()

def examA():
    class UnionFind():
        def __init__(self, n):
            self.parent = [-1 for _ in range(n)]
            # 正==子: 根の頂点番号 / 負==根: 連結頂点数

        def reset(self):
            self.parent = [-1] * len(self.parent)

        def find(self, x):
            # 要素xが属するグループの根を返す
            if self.parent[x] < 0:
                return x
            else:
                self.parent[x] = self.find(self.parent[x])
                return self.parent[x]

        def unite(self, x, y):
            # 要素xが属するグループと要素yが属するグループとを併合する
            x, y = self.find(x), self.find(y)
            if x == y:
                return False
            else:
                if self.size(x) < self.size(y):
                    x, y = y, x
                self.parent[x] += self.parent[y]
                self.parent[y] = x

        def same(self, x, y):
            # 要素x, yが同じグループに属するかどうかを返す
            return self.find(x) == self.find(y)

        def size(self, x):
            # 要素xが属するグループのサイズ（要素数）を返す
            x = self.find(x)
            return -self.parent[x]

        def is_root(self, x):
            # 要素の根をリストで返す
            return self.parent[x] < 0

        def roots(self):
            # すべての根の要素をリストで返す
            return [i for i, x in enumerate(self.parent) if x < 0]

        def members(self, x):
            # 要素xが属するグループに属する要素をリストで返す
            root = self.find(x)
            return [i for i in range(self.n) if self.find(i) == root]

        def group_count(self):
            # グループの数を返す
            return len(self.roots())

        def all_group_members(self):
            # {ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す
            return {r: self.members(r) for r in self.roots()}
    N = I()
    XY = [LI()+[i] for i in range(N)]
    XY.sort()
    #print(XY)
    que = []
    ans = [0]*N
    uf = UnionFind(N)
    for _,y,i in XY:
        if not que:
            heappush(que,[y,i])
        else:
            miny, mini = heappop(que)
            if miny<y:
                uf.unite(i, mini)
                while (que):
                    ny, ni = heappop(que)
                    if ny < y:
                        uf.unite(i, ni)
                        #print(i, ni)
                    else:
                        heappush(que, [ny, ni])
                        break
            else:
                heappush(que, [y, i])
            heappush(que, [miny, mini])

    for i in range(N):
        ans[i] = uf.size(i)
    for v in ans:
        print(v)
    return

def examB():
    ans = 0
    print(ans)
    return

def examC():
    ans = 0
    print(ans)
    return

def examD():
    ans = 0
    print(ans)
    return

def examE():
    ans = 0
    print(ans)
    return

def examF():
    ans = 0
    print(ans)
    return

from decimal import getcontext,Decimal as dec
import sys,bisect,itertools,heapq,math,random
from copy import deepcopy
from heapq import heappop,heappush,heapify
from collections import Counter,defaultdict,deque
read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines
def I(): return int(input())
def LI(): return list(map(int,sys.stdin.readline().split()))
def DI(): return dec(input())
def LDI(): return list(map(dec,sys.stdin.readline().split()))
def LSI(): return list(map(str,sys.stdin.readline().split()))
def LS(): return sys.stdin.readline().split()
def SI(): return sys.stdin.readline().strip()
global mod,mod2,inf,alphabet,alphabet_convert,_ep
mod = 10**9 + 7
mod2 = 998244353
inf = 1<<31
_ep = dec("0.000000000001")
alphabet = [chr(ord('a') + i) for i in range(26)]
alphabet_convert = {chr(ord('a') + i): i for i in range(26)}

getcontext().prec = 28

sys.setrecursionlimit(10**7)

if __name__ == '__main__':
    main()

"""
142
12 9 1445 0 1
asd dfg hj o o
aidn
"""

Submission status: Accepted

Solution code:
class BIT:
  def __init__(self, n):
    self.n = n
    self.data = [0]*(n+1)
    self.el = [0]*(n+1)
  def sum(self, i):
    s = 0
    while i > 0:
      s += self.data[i]
      i -= i & -i
    return s
  def add(self, i, x):
    # assert i > 0
    self.el[i] += x
    while i <= self.n:
      self.data[i] += x
      i += i & -i
  def get(self, i, j=None):
    if j is None:
      return self.el[i]
    return self.sum(j) - self.sum(i)


n=int(input())
xy=[list(map(int,input().split())) for _ in range(n)]
xy=[(i,x,y)for i,(x,y) in enumerate(xy)]
xy.sort(key=lambda x:x[1])
g=[set() for _ in range(n)]
bit=BIT(n)
work=[-1]*(n+1)
for i,x,y in xy:
  k=bit.sum(y)
  l,r=1,y+1
  c=y+1
  for j in range(k,0,-1):
    l,r=1,c
    while r-l>1:
      c=(r+l)//2
      if bit.sum(c)>=j:
        l,r=l,c
      else:
        l,r=c,r
    c=l if bit.sum(l)==j else r
    idx=work[c]
    g[idx].add(i)
    g[i].add(idx)
    if j>1:bit.add(c,-1)
  if k==0:bit.add(y,1)
  if k==0:work[y]=i

ans=[0]*n
mi=set(range(n))
while mi:
  s=mi.pop()
  grp={s}
  todo=[s]
  cnt=1
  while todo:
    v=todo.pop()
    for nv in g[v]:
      if nv not in grp:
        todo.append(nv)
        grp.add(nv)
        mi.discard(nv)
        cnt+=1
  for id in grp:
    ans[id]=cnt
print(*ans,sep='\n')
#print(g)
#print(bit.sum(1))

Submission status: Accepted

Solution code:
# Reference: https://note.nkmk.me/python-union-find/
class UnionFind:
    # if x is root: self.parents[x] = -(the number of the group nodes)
    # else: self.parents[x] = the parent of x
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    # return the parent of x
    def find(self, x):
        history = []
        while self.parents[x] >= 0:
            history.append(x)
            x = self.parents[x]
        for node in history:
            self.parents[node] = x
        return x

    # merge the group of x and the group of y
    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.parents[x] > self.parents[y]:
            x, y = y, x
        self.parents[x] += self.parents[y]
        self.parents[y] = x

    # return the size of the group of x
    def size(self, x):
        return -self.parents[self.find(x)]

from sys import stdin
input = stdin.buffer.readline

def main():
    n = int(input())

    l = [0] * n
    for i in range(n):
        x, y = map(int, input().split())
        l[x-1] = (y-1, i)

    uf = UnionFind(n)
    roots = []

    for y, i in l:
        if len(roots) == 0 or roots[-1][0] > y:
            roots.append((y, i))
        else:
            new_y = roots[-1][0]
            while len(roots) > 0 and roots[-1][0] < y:
                old_y, old_i = roots.pop()
                uf.union(i, old_i)
            roots.append((new_y, i))

    # O(uf.size(i)) = 1
    for i in range(n):
        print(uf.size(i))

main()

Submission status: Accepted

Solution code:
def getN():
    return int(input())
def getNM():
    return map(int, input().split())
def getList():
    return list(map(int, input().split()))
def getArray(intn):
    return [int(input()) for i in range(intn)]
def input():
    return sys.stdin.readline().rstrip()
def rand_N(ran1, ran2):
    return random.randint(ran1, ran2)
def rand_List(ran1, ran2, rantime):
    return [random.randint(ran1, ran2) for i in range(rantime)]
def rand_ints_nodup(ran1, ran2, rantime):
  ns = []
  while len(ns) < rantime:
    n = random.randint(ran1, ran2)
    if not n in ns:
      ns.append(n)
  return sorted(ns)

def rand_query(ran1, ran2, rantime):
  r_query = []
  while len(r_query) < rantime:
    n_q = rand_ints_nodup(ran1, ran2, 2)
    if not n_q in r_query:
      r_query.append(n_q)
  return sorted(r_query)

from collections import defaultdict, deque, Counter
from sys import exit
from decimal import *
from heapq import heapify, heappop, heappush
import math
import random
import string
from copy import deepcopy
from itertools import combinations, permutations, product
from operator import mul, itemgetter
from functools import reduce
from bisect import bisect_left, bisect_right

import sys
sys.setrecursionlimit(1000000000)
mod = 10 ** 9 + 7

#############
# Main Code #
#############

class UnionFind:
    def __init__(self, N):
        """
        N:要素数
        root:各要素の親要素の番号を格納するリスト.
             ただし, root[x] < 0 ならその頂点が根で-root[x]が木の要素数.
        rank:ランク
        """
        self.N = N
        self.root = [-1] * N
        self.rank = [0] * N

    def __repr__(self):
        return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

    def find(self, x):
        """頂点xの根を見つける"""
        if self.root[x] < 0:
            return x
        else:
            while self.root[x] >= 0:
                x = self.root[x]
            return x

    def union(self, x, y):
        """x,yが属する木をunion"""
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        elif self.rank[x] > self.rank[y]:
            self.root[x] += self.root[y]
            self.root[y] = x
        else:
            self.root[y] += self.root[x]
            self.root[x] = y
            if self.rank[x] == self.rank[y]:
                self.rank[y] += 1

    def same(self, x, y):
        """xとyが同じグループに属するかどうか"""
        return self.find(x) == self.find(y)

    def count(self, x):
        """頂点xが属する木のサイズを返す"""
        return - self.root[self.find(x)]

    def members(self, x):
        """xが属する木の要素を列挙"""
        _root = self.find(x)
        return [i for i in range(self.N) if self.find == _root]

    def roots(self):
        """森の根を列挙"""
        return [i for i, x in enumerate(self.root) if x < 0]

    def group_count(self):
        """連結成分の数"""
        return len(self.roots())

    def all_group_members(self):
        """{ルート要素: [そのグループに含まれる要素のリスト], ...}の辞書を返す"""
        return {r: self.members(r) for r in self.roots()}

N = getN()
Q = [getList() for i in range(N)]
que = deepcopy(Q)
que.sort(key = lambda i:i[1], reverse = True)
que.sort()

# xy座標が共に大きいもの
# 順列になっている？

"""
O(n**2)
U = UnionFind(N)
for i in range(N):
    for j in range(i + 1, N):
        if que[i][1] < que[j][1]:
            U.union(i, j)
for i in range(N):
    print(U.count(i))
"""
#　ソート方法はこれでOK
# やらなくていい探索がある　それを減らす
# 4 3
# 4 1
# 4 2
# 3 1
# 3 2
# 1 2 これだけいる

# 4 3 1 2でi < jになるものをペアに
# 1とペアにできるのは2, 3, 4
# 2とペアにできるのは3, 4
# 3は4
# それぞれ右側にあれば

# 6 7 5 3 2 4 1
# グループ１ 6 7
# グループ2 5
# グループ3 3 2 4
# グループ4 1
# どれか１つのグループに属する

U = UnionFind(N + 1)
group = []

for x, y in que:
    # １番目のものは必ずグループのリーダーになれる
    if not group:
        group.append(y)
        continue
    # リーダーが降順に並ぶように
    if y < group[-1]:
        group.append(y)
        continue
    opt = float('inf')
    # グループ再編成
    while group:
        # yより小さいものは全てyが所属するグループに入る
        if y > group[-1]:
            l = group.pop()
            U.union(l, y)
            opt = min(opt, l) # yが所属するグループの中のリーダー　一番最初のものが記録される
        else:
            break
    # リーダー変更
    group.append(opt)

for i in range(N):
    print(U.count(Q[i][1])) # yがiのもののサイズの大きさ　uf.funcはインデックスで呼ばなくてもいい

Submission status: Accepted

Solution code:
# でつoO(YOU PLAY WITH THE CARDS YOU'RE DEALT..)
from typing import Iterable
import sys
def main(N, XY):
    uf = UnionFindTree(N)
    miny = []
    for x, y in sorted(XY, key=lambda x: x[0]):
        if not miny:
            miny.append(y)
            continue
        if y < miny[-1]:
            miny.append(y)
            continue
        t = 10**10
        while miny:
            if y > miny[-1]:
                py = miny.pop()
                uf.union(py, y)
                t = min(t, py)
            else:
                break
        miny.append(t)
    for x, y in XY:
        print(uf.size(y))

class UnionFindTree:
    def __init__(self, n: int) -> None:
        self.parent = [-1] * n

    def find(self, x: int) -> int:
        p = self.parent
        while p[x] >= 0: x, p[x] = p[x], p[p[x]]
        return x

    def union(self, x: int, y: int) -> bool:
        x, y, p = self.find(x), self.find(y), self.parent
        if x == y: return False
        if p[x] > p[y]: x, y = y, x
        p[x], p[y] = p[x] + p[y], x
        return True

    def same(self, x: int, y: int) -> bool:
        return self.find(x) == self.find(y)

    def size(self, x: int) -> int:
        return -self.parent[self.find(x)]

    def same_all(self, indices: Iterable[int]) -> bool:
        f, v = self.find, self.find(indices[0])
        return all(f(i) == v for i in indices)

if __name__ == '__main__':
    input = sys.stdin.readline
    N = int(input())
    XY = [tuple(map(lambda x:int(x) - 1, input().split())) for _ in range(N)]
    main(N, XY)

Submission status: Accepted

Solution code:
import sys
from collections import deque
input = sys.stdin.readline


class UnionFind:
    def __init__(self, n):
        self.n = n
        self.par = [-1]*(n+1)#それぞれの要素がどの要素の子であるか

    def find(self, x):
        if self.par[x] < 0:
            return x
        else:
            self.par[x] = self.find(self.par[x])
            return self.par[x]#それぞれの要素の根を再帰的に求める

    def union(self, x, y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return
        if self.par[x] > self.par[y]:
            x, y = y, x
        
        self.par[x] += self.par[y]
        self.par[y] = x

    def same(self, x, y):
        return self.find(x) == self.find(y)#x,yが同じ集合に属するかどうか
    
    def size(self, x):
        return -self.par[self.find(x)]
    
    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if root == self.find(i)]        


def main():
    n = int(input())
    town = [list(map(int, input().split())) + [i] for i in range(n)]

    town.sort()
    union = UnionFind(n)
    already = deque([])

    for x, y, i in town:
        if not already:
            already.append((y, i))
            continue
        key = already.pop()
        if key[0] > y:
            already.append(key)
            already.append((y, i))
            continue
        sub = key
        while already:
            union.union(sub[1], i)
            sub = already.pop()
            if sub[0] > y:
                break
        if not already and sub[0] < y:
            union.union(sub[1], i)
        else:
            already.append(sub)
        already.append(key)
    
    ans = [0]*n
    for i in range(n):
        ans[i] = union.size(i)
    
    print(*ans, sep="\n")





    
if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

class Unionfind:
     
    def __init__(self,n):
        self.uf = [-1]*n
 
    def find(self,x):
        if self.uf[x] < 0:
            return x
        else:
            self.uf[x] = self.find(self.uf[x])
            return self.uf[x]
 
    def same(self,x,y):
        return self.find(x) == self.find(y)
 
    def union(self,x,y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.uf[x] > self.uf[y]:
            x,y = y,x
        self.uf[x] += self.uf[y]
        self.uf[y] = x
        return True
 
    def size(self,x):
        x = self.find(x)
        return -self.uf[x]


n = int(input())
xy = [list(map(int,input().split())) for i in range(n)]
xy2 = [[x[0],x[1],i] for (i,x) in enumerate(xy)]
xy2.sort()
u = Unionfind(n)

l = []
for x,y,ind in xy2:
    M = y
    le = ind
    while l and xy[l[-1]][1] < y:
        v = l.pop()
        if M > xy[v][1]:
            M = xy[v][1]
            le = v
        u.union(ind,v)
    l.append(le)
for i in range(n):
    print(u.size(i))

Submission status: Accepted

Solution code:
import sys
input = sys.stdin.readline

class Unionfind:
     
    def __init__(self,n):
        self.uf = [-1]*n
 
    def find(self,x):
        if self.uf[x] < 0:
            return x
        else:
            self.uf[x] = self.find(self.uf[x])
            return self.uf[x]
 
    def same(self,x,y):
        return self.find(x) == self.find(y)
 
    def union(self,x,y):
        x = self.find(x)
        y = self.find(y)
        if x == y:
            return False
        if self.uf[x] > self.uf[y]:
            x,y = y,x
        self.uf[x] += self.uf[y]
        self.uf[y] = x
        return True
 
    def size(self,x):
        x = self.find(x)
        return -self.uf[x]

def main():
    n = int(input())
    xy = [list(map(int,input().split())) for i in range(n)]
    xy2 = [[x[0],x[1],i] for (i,x) in enumerate(xy)]
    xy2.sort()
    u = Unionfind(n)

    l = []
    for x,y,ind in xy2:
        M = y
        le = ind
        while l and xy[l[-1]][1] < y:
            v = l.pop()
            if M > xy[v][1]:
                M = xy[v][1]
                le = v
            u.union(ind,v)
        l.append(le)
    for i in range(n):
        print(u.size(i))

if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
class UnionFind():
  def __init__(self, n):
    self.n = n
    self.parents = [-1] * n
    self.min_y = [N]*n

  def find(self, x):
    if self.parents[x] < 0:
      return x
    else:
      self.parents[x] = self.find(self.parents[x])
    return self.parents[x]

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

    if x == y:
      return

    if self.parents[x] > self.parents[y]:
      x, y = y, x

    self.parents[x] += self.parents[y]
    self.min_y[x] = min(self.min_y[x],self.min_y[y])
    self.parents[y] = x

  def same(self, x, y):
    return self.find(x) == self.find(y)

  def roots(self):
    return [i for i, x in enumerate(self.parents) if x < 0]

  def num_roots(self):
    return len([i for i, x in enumerate(self.parents) if x < 0])

  def members(self, x):
    root = self.find(x)
    return [i for i in range(self.n) if self.find(i) == root]

  def num_members(self,x):
    return abs(self.parents[self.find(x)])

  def __str__(self):
    return '\n'.join('{}: {}'.format(r, self.members(r)) for r in self.roots())

import sys,os,io
input = sys.stdin.readline
# input = io.BytesIO(os.read(0,os.fstat(0).st_size)).readline
N = int(input())
A = [list(map(int, input().split()))+[i] for i in range(N)]
uf = UnionFind(N)
uf.min_y = [y for x,y,i in A]
ans = [1]*N
A.sort()
Y = [(i,y) for x,y,i in A]
from heapq import *
heap = []
for u,y in Y:
  atode = []
  for _ in range(len(heap)):
    y1,v = heappop(heap)
    if y<y1:
      heappush(heap,(y1,v))
      break
    uf.union(u,v)
    if uf.parents[v]<0:
      atode.append((uf.min_y[v],v))
  if uf.parents[u]<0:
    heappush(heap,(uf.min_y[u],u))
  for y1,v in atode:
    heappush(heap,(y1,v))
for i in range(N):
  ans[i] = uf.num_members(i)
print(*ans, sep='\n')

Submission status: Accepted

Solution code:
from heapq import heappush, heappop

class UnionFind:
    def __init__(self, size):
        self.data = [-1] * size
    def find(self, x):
        if self.data[x] < 0:
            return x
        else:
            self.data[x] = self.find(self.data[x])
            return self.data[x]
    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x != y:
            if self.data[y] < self.data[x]:
                x, y = y, x
            self.data[x] += self.data[y]
            self.data[y] = x
        return (x != y)
    def same(self, x, y):
        return (self.find(x) == self.find(y))
    def size(self, x):
        return -self.data[self.find(x)]

N, *XY = map(int, open(0).read().split())
YtoI = {y : i for i, y in enumerate(XY[1::2])}

uf = UnionFind(N)
Q = []
for x, y in sorted(zip(*[iter(XY)] * 2)):
    heappush(Q, y)
    mi = Q[0]
    while Q and Q[0] <= y:
        uf.union(YtoI[y], YtoI[heappop(Q)])
    heappush(Q, mi)

for i in range(N):
    print(uf.size(i))

Submission status: Accepted

Solution code:
from heapq import heappush, heappop

class UnionFind:
    def __init__(self, size):
        self.data = [-1] * size
    def find(self, x):
        if self.data[x] < 0:
            return x
        else:
            self.data[x] = self.find(self.data[x])
            return self.data[x]
    def union(self, x, y):
        x, y = self.find(x), self.find(y)
        if x != y:
            if self.data[y] < self.data[x]:
                x, y = y, x
            self.data[x] += self.data[y]
            self.data[y] = x
        return (x != y)
    def same(self, x, y):
        return (self.find(x) == self.find(y))
    def size(self, x):
        return -self.data[self.find(x)]

N, *XY = map(int, open(0).read().split())
XY = list(zip(*[iter(XY)] * 2))

YtoI = {y : i for i, (x, y) in enumerate(XY)}

XY.sort()

uf = UnionFind(N)
Q = []
for x, y in XY:
    T = []
    while Q and Q[0] < y:
        yy = heappop(Q)
        uf.union(YtoI[y], YtoI[yy])
        T.append(yy)

    if T:
        heappush(Q, T[0])
    else:
        heappush(Q, y)


for i in range(N):
    print(uf.size(i))

Submission status: Accepted

Solution code:
n = int(input())
xy = []
idx = [None]*n
ys = [None]*n
ans = [None]*n
accumx = [None]*n
accumn = [None]*n
for i in range(n):
    x, y = map(int, input().split())
    idx[x-1] = i
    ys[x-1] = y-1
accumx[-1] = ys[-1]
for i in range(n-2, -1, -1):
    accumx[i] = max(accumx[i+1], ys[i])
accumn[0] = ys[0]
for i in range(1, n):
    accumn[i] = min(accumn[i-1], ys[i])

def bisect(x):
    ok = 0
    ng = n
    while abs(ok-ng)>1:
        mid = (ok+ng)//2
        if accumx[mid]>x:
            ok = mid
        else:
            ng = mid
    return ok

nowx = 0
while nowx<n:
    nxtx = nowx
    tmp = bisect(ys[nowx])
    while tmp>nxtx:
        nxtx = tmp
        tmp = bisect(accumn[nxtx])
    if nxtx<nowx:
        nxtx = nowx
    for i in range(nowx, nxtx+1):
        ans[idx[i]] = nxtx-nowx+1
    nowx = nxtx + 1
print(*ans, sep='\n')

Submission status: Accepted

Solution code:
import sys
def input(): return sys.stdin.readline().strip()
def mapint(): return map(int, input().split())
sys.setrecursionlimit(10**9)

N = int(input())
idx_dic = {}
XY = []
for i in range(N):
    x, y = mapint()
    x, y = x-1, y-1
    idx_dic[i] = y
    XY.append((x, y))
XY.sort()

class UnionFind():
    def __init__(self, n):
        self.n = n
        self.parents = [-1] * n

    def find(self, x):
        if self.parents[x] < 0:
            return x
        else:
            self.parents[x] = self.find(self.parents[x])
            return self.parents[x]

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

        if x == y:
            return

        if self.parents[x] > self.parents[y]:
            x, y = y, x

        self.parents[x] += self.parents[y]
        self.parents[y] = x

    def size(self, x):
        return -self.parents[self.find(x)]

    def same(self, x, y):
        return self.find(x) == self.find(y)

    def members(self, x):
        root = self.find(x)
        return [i for i in range(self.n) if self.find(i) == root]

    def roots(self):
        return [i for i, x in enumerate(self.parents) if x < 0]

    def group_count(self):
        return len(self.roots())

    def all_group_members(self):
        return {r: self.members(r) for r in self.roots()}

uf = UnionFind(N)
from heapq import heappush, heappop
Q = []
for i in range(N):
    x, y = XY[i]
    mini = None
    while Q:
        v = heappop(Q)
        if v>y:
            heappush(Q, v)
            break
        uf.union(v, y)
        if mini is None:
            mini = v
    if mini is None:
        heappush(Q, y)
    else:
        heappush(Q, mini)
for i in range(N):
    print(uf.size(idx_dic[i]))