Music Festival (Codeforces 1801C)
Tags: Greedy, binary search

 The boy Vitya loves to listen to music very much. He knows that $$$n$$$ albums are due to be released this Friday, $$$i$$$-th of which contains $$$k_i$$$ tracks. Of course, Vitya has already listened to all the tracks, and knows that in the $$$i$$$-th album, the coolness of the $$$j$$$-th track is equal to $$$a_{i,j}$$$.Vitya has a friend Masha, whom he really wants to invite to the festival, where his favorite bands perform. However, in order for a friend to agree, she must first evaluate the released novelties. Vitya knows that if Masha listens to a track that was cooler than all the previous ones, she will get 1 unit of impression. Unfortunately, albums can only be listened to in their entirety, without changing the songs in them in places.Help Vitya find such an order of albums so that Masha's impression turns out to be as much as possible, and she definitely went to the festival with him. 

Input: Each test consists of multiple test cases. The first line contains a single integer t ($$$1 \le t \le 200\,000$$$) — the number of test cases. The description of test cases follows.The first line of each test case contains a single integer $$$n$$$ ($$$1 \le n \le 200\,000$$$) — number of albums.The album descriptions follow. Each album description consists of two lines:The first line contains a single integer $$$k_i$$$ ($$$1 \le k_i \le 200\,000$$$) — the number of tracks in the $$$i$$$th album.The following line contains $$$k_i$$$ integers $$$a_{i, 1},\ a_{i, 2},\ a_{i, 3},\ \ldots,\ a_{i, k_i}$$$ ($$$1 \le a_{i,j} \le 200\,000$$$) — the coolness of the tracks in the $$$i$$$ album. Denote for $$$\sum k_i$$$ the sum of all $$$k_i$$$. It is guaranteed that $$$\sum k_i \le 200\,000$$$. 

Output: For each test case print the singular number  — the maximum impression that Masha can get. 

Note: In the first test example, the optimal order is listening to the 4th, 2nd, 3rd and 1st albums. In this case, Masha will listen to the tracks in the following order: 1; 7; 8, 6; 4, 9, 4, 6, 8 and will receive 4 units of impression.In the second test example, you must first listen to the 1st, then the 4th, and in any order the 2nd and 3rd.   In this case, Masha will get the maximum impression, and for every song in the 1st and 4th albums and nothing for the 2nd and 3rd. 

Sample Inputs:
2
4
5
4 9 4 6 8
1
7
2
8 6
1
1
4
2
3 4
2
1 8
2
2 8
2
7 9

Sample Outputs:
4
4

Solution (Python):
import sys
from os import path
if path.exists('Input.txt'):
    sys.stdin = open('Input.txt', 'r')
    sys.stdout = open('Output.txt', 'w')
input = sys.stdin.buffer.readline
print = sys.stdout.write
from random import randint

class mydict:

    def __init__(self, func=lambda : 0):
        self.random = randint(0, 1 << 32)
        self.default = func
        self.dict = {}

    def __getitem__(self, key):
        mykey = self.random ^ key
        if mykey not in self.dict:
            self.dict[mykey] = self.default()
        return self.dict[mykey]

    def get(self, key, default):
        mykey = self.random ^ key
        if mykey not in self.dict:
            return default
        return self.dict[mykey]

    def __setitem__(self, key, item):
        mykey = self.random ^ key
        self.dict[mykey] = item

    def getkeys(self):
        return [self.random ^ i for i in self.dict]

    def __str__(self):
        return f'{[(self.random ^ i, self.dict[i]) for i in self.dict]}'

def solve():
    n = int(input())
    l = []
    last = [0 for i in range(n)]
    for i in range(n):
        k = int(input())
        a = [int(x) for x in input().split()]
        cur = 0
        for ii in a:
            if ii > cur:
                cur = ii
                l.append([ii, i])
                last[i] = ii
    l.sort(key=lambda x: (x[0], x[1]))
    dp = [0 for i in range(len(l))]
    mx = [0 for i in range(n)]
    mx_end = 0
    i = 0
    while i < len(l):
        (val, idx) = l[i]
        dp[i] = max(1 + mx_end, 1 + mx[idx])
        mx[idx] = max(mx[idx], dp[i])
        helper_mx_end = 0
        if val == last[idx]:
            helper_mx_end = max(helper_mx_end, dp[i])
        i += 1
        val2 = val
        while i < len(l) and l[i][0] == val2:
            (val, idx) = l[i]
            dp[i] = max(1 + mx_end, 1 + mx[idx])
            mx[idx] = max(mx[idx], dp[i])
            if val == last[idx]:
                helper_mx_end = max(helper_mx_end, dp[i])
            i += 1
        mx_end = max(mx_end, helper_mx_end)
    print(str(max(dp)) + '\n')
for _ in range(int(input())):
    solve()

Solution (Python):
import math
import heapq
import itertools
import bisect
import random
import time
from collections import deque
import sys
from cmath import exp, pi
input = sys.stdin.readline
t = int(input())
for _ in range(t):
    n = int(input())
    arr = []
    num = []
    for _ in range(n):
        x = int(input())
        line = list(map(int, input().split()))
        newline = [0]
        for i in line:
            if newline[-1] < i:
                newline.append(i)
        num += newline[1:]
        arr.append(newline[1:])
    num = sorted(list(set(num)))
    dp = [0 for _ in range(len(num) + 1)]
    check = [[] for _ in range(len(num) + 1)]
    for i in range(n):
        for j in range(len(arr[i])):
            arr[i][j] = bisect.bisect_left(num, arr[i][j])
        check[arr[i][-1] + 1].append(i)
    dp.append(0)
    for i in range(len(dp) - 2, -1, -1):
        dp[i] = max(dp[i], dp[i + 1])
        for j in check[i]:
            for j2 in range(len(arr[j])):
                dp[arr[j][j2]] = max(dp[arr[j][j2]], dp[i] + len(arr[j]) - j2)
    print(dp[0])

Solution (Python):
import sys
import math
import random
from collections import deque
from queue import Queue
import copy
input = sys.stdin.readline

def fg():
    return int(input())

def fgh():
    return [int(xx) for xx in input().split()]

def bs():
    return [xx == '1' for xx in input()[:-1]]

def yes():
    print('YES')

def no():
    print('NO')

def ff():
    sys.stdout.flush()
for _ in range(fg()):
    k = fg()
    a = [[] for i in range(k)]
    keys = set()
    mx_end = dict()
    for i in range(k):
        nn = fg()
        b = fgh()
        a[i].append(b[0])
        keys.add(b[0])
        for j in range(1, nn):
            if b[j] > a[i][-1]:
                a[i].append(b[j])
                keys.add(b[j])
        if len(mx_end.get(a[i][-1], [])) == 0:
            mx_end[a[i][-1]] = [i]
        else:
            mx_end[a[i][-1]].append(i)
    keys = sorted(list(keys))
    n = len(keys)
    get_key = dict()
    for i in range(n):
        get_key[keys[i]] = i
    dp = [0] * (n + 1)
    for i in range(n):
        dp[i + 1] = dp[i] + 0
        if len(mx_end.get(keys[i], [])) > 0:
            for j in range(len(mx_end[keys[i]])):
                for p in range(len(a[mx_end[keys[i]][j]]) - 1, -1, -1):
                    dp[i + 1] = max(dp[i + 1], dp[get_key[a[mx_end[keys[i]][j]][p]]] + len(a[mx_end[keys[i]][j]]) - p)
    print(dp[-1])