Problem:


勉強会

プログラマー養成校のアカベ高校には、生徒自身で運営するユニークな勉強会があります。プログラマーは新しい技術を常に取り入れることが大切なので、この勉強会を通して自学自習の習慣を身につけることがこの活動のねらいです。

生徒は全部でN人おり、それぞれが入学時のプログラミングコンテストの結果で得られたスコアを持っています。勉強会ではN人の生徒のうち何人かがリーダーになり、各リーダーがそれぞれのグループを運営するとともに、自らの運営するグループに参加します。

リーダー以外の生徒は、自分のスコアよりも低いスコアのリーダーが運営するグループには参加できません。また、0以上のある値rを１つ決め、グループに参加する生徒とリーダーのスコアの差がr以内となるようにしています。つまり、グループのリーダーのスコアがsのとき、自分のスコアがsを超えているか、あるいは s - r 未満ならば、そのグループには参加できません。

あなたは勉強会の実行委員長であり、運営準備のためにシミュレーションを行うことにしました。シミュレーションでは、リーダーが誰もいない状態から始め、以下の操作を何回か繰り返します。

 生徒をリーダーに加える。

 生徒をリーダーから外す。

 要求時点でのリーダーの組み合わせについて、どのグループにも参加できない生徒がx人以下になるような、最小のrを求める。

このようなシミュレーションを行うプログラムを作成してください。

入力

入力は1つのデータセットからなる。入力は以下の形式で与えられる。

N Q
s1
s2
:
sN
QUERY1
QUERY2
:
QUERYQ

1行目に生徒の数N(1 ≤ N ≤ 1000000)、処理要求の数Q(0 ≤ Q ≤ 1000)が与えられる。

続くN行にi番目の生徒のスコアを示す整数si(0 ≤ si ≤ 1,000,000,000)が与えられる。生徒は1,2,...,N で番号付けされているものとする。

続くQ行に処理要求QUERYiが与えられる。処理要求は時系列順に与えられる。処理要求はADD, REMOVE, CHECKの3種類あり、各QUERYiは以下のいずれかの形式で与えられる。

ADD a

または

REMOVE a

または

CHECK x

ADD aは番号a(1 ≤ a ≤ N)の生徒をリーダーに加えることを表す。

REMOVE aは番号a(1 ≤ a ≤ N)の生徒をリーダーから外すことを表す。

CHECK xは出力要求を表す。どのグループにも参加できない生徒の数の上限x(0 ≤ x ≤ N)が与えられる。

なお、入力は以下の条件を満たすものとする。

 どの時点でも、リーダーの人数が100人を超えることはない。

 その時点でリーダーである生徒をリーダーに加えることはない。

 その時点でリーダーでない生徒をリーダーから外すことはない。

出力

時系列順に各出力要求の時点で、どのグループにも参加できない生徒がx人以下になるような最小のrを1行に出力する。ただし、どのようなrを選んでもx人以下にすることが不可能であればNAと出力する。

入力例 1

5 8
5
10
8
7
3
ADD 1
ADD 3
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5

出力例 1

NA
2
1
0
0
0

入力例 2

5 28
5
10
8
7
3
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5
ADD 1
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5
REMOVE 1
ADD 3
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5
ADD 1
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5

出力例 2

NA
NA
NA
NA
NA
0
NA
NA
NA
2
0
0
NA
5
3
1
0
0
NA
2
1
0
0
0



Sample input:
5 8
5
10
8
7
3
ADD 1
ADD 3
CHECK 0
CHECK 1
CHECK 2
CHECK 3
CHECK 4
CHECK 5


Sample output:
NA
2
1
0
0
0

Submission status: Wrong Answer

Solution code:
def get_count(s, leader, r):
    count = 0
    
    pre_upper_pos = 0
    
    for li in leader:
        lower_pos = bisect.bisect_left(s, li - r)
        upper_pos = bisect.bisect_right(s, li)
        if pre_upper_pos < lower_pos:
            count += lower_pos - pre_upper_pos
        pre_upper_pos = upper_pos
    count += len(s) - pre_upper_pos
    
    return count

import bisect

def check(s,leader,target_x):
    if 0 == len(leader):
        return 'NA'
    min_x = len(s) - bisect.bisect_right(s, leader[-1])
    if target_x < min_x:
        return 'NA'

    l, r = 0, s[-1]
    diff = r - 1
    while True:
        m = (l + r) // 2
        x = get_count(s, leader, m)
        if target_x < x:
            l = m
        elif x <= target_x:
            r = m
        
        if diff == l - r:
            return r
        diff = l - r

import sys
f = sys.stdin

n, q = (int(i) for i in  f.readline().split())
s = [int(f.readline()) for i in range(n)]
query = [line.split() for line in f]

sort_s = sorted(s)
leader = []

for op, a in query:
    a = int(a)
    if op[0] == 'A':
        leader.append(s[a - 1]) #bisect??§??????????¶?????????????????????\?????????
        leader.sort()
    elif op[0] == 'R':
        leader.remove(s[a - 1])
    else:
        r = check(sort_s,leader,a)
        print(r)

Submission status: Time Limit Exceeded

Solution code:
from bisect import bisect_left as bl
def check(x):
    if x >= len(M):
        print 0
    else:
        r = sorted([L[bl(L, n)] - n for n in M])
        print  r[-x - 1] if r[-x - 1] != float("inf") else "NA"

N, Q = map(int, raw_input().split())
M = [int(raw_input()) for _ in xrange(N)]
L = [float("inf")]
f = {"ADD": lambda x: L.insert(bl(L, M[x - 1]), M[x - 1]),
     "REMOVE":lambda x: L.remove(M[x - 1]),
     "CHECK": check}
for _ in xrange(Q):
    q, x = raw_input().split()    
    f[q](int(x))

Submission status: Accepted

Solution code:
def get_count(s, leader, r):
    count = 0
    
    pre_upper_pos = 0
    
    for li in leader:
        lower_pos = bisect.bisect_left(s, li - r)
        upper_pos = bisect.bisect_right(s, li)
        if pre_upper_pos < lower_pos:
            count += lower_pos - pre_upper_pos
        pre_upper_pos = upper_pos
    count += len(s) - pre_upper_pos
    
    return count

import bisect

def check(s,leader,target_x):
    if 0 == len(leader):
        if target_x < len(s):
            return 'NA'
        else:
            return 0
    min_x = len(s) - bisect.bisect_right(s, leader[-1])
    if target_x < min_x:
        return 'NA'

    l, r = 0, s[-1]
    diff = r - 1
    while True:
        m = (l + r) // 2
        x = get_count(s, leader, m)
        if target_x < x:
            l = m
        elif x <= target_x:
            r = m
        
        if diff == l - r:
            return r
        diff = l - r

import sys
f = sys.stdin

n, q = (int(i) for i in  f.readline().split())
s = [int(f.readline()) for i in range(n)]
query = [line.split() for line in f]

sort_s = sorted(s)
leader = []

for op, a in query:
    a = int(a)
    if op[0] == 'A':
        leader.append(s[a - 1]) #bisect??§??????????¶?????????????????????\?????????
        leader.sort()
    elif op[0] == 'R':
        leader.remove(s[a - 1])
    else:
        r = check(sort_s,leader,a)
        print(r)

Submission status: Accepted

Solution code:
import bisect

INF = int(10**9+1)

n, q = map(int, input().split())
tmp = [ (int(input()),i) for i in range(n) ]
tmp.sort()
s = [0]*n
f = [0]*n
i = 0
for key,val in tmp :
    s[i] = key
    f[val] = i
    i += 1

leader = []
while q > 0 :
    line = input().split()
    arg = int(line[1])
    #print(line)
    if line[0] == 'ADD':
        idx = bisect.bisect_left( leader, f[arg-1] )
        leader = leader[:idx] + [f[arg-1]] + leader[idx:]
    elif line[0] == 'REMOVE':
        leader.remove( f[arg-1] )
    else: #CHECK
        fail_r = -1
        succ_r = INF
        while succ_r - fail_r > 1 :
            mid = int((succ_r + fail_r)/2)
            count = 0
            prev = -1
            for idx in leader :
                l_idx = bisect.bisect_left( s, s[idx]-mid )
                r_idx = bisect.bisect_right( s, s[idx] ) - 1
                if l_idx <= prev : l_idx = prev + 1
                count += r_idx - l_idx + 1
                prev = r_idx

            if n - count <= arg : succ_r = mid
            else : fail_r = mid

        if succ_r == INF : print('NA')
        else : print(succ_r)

#    for idx in leader : print(idx)
    
    q -= 1

Submission status: Accepted

Solution code:
from bisect import bisect
import operator
import sys
from collections import defaultdict
readline = sys.stdin.readline
write = sys.stdout.write

N, Q = map(int, readline().split())
R = [int(readline()) for i in range(N)]
S = list(set(R))
S.sort()
mp = {e: i for i, e in enumerate(S)}
D = defaultdict(int)

T = R[:]
T.sort()
mpm = {}
for i, e in enumerate(T):
    mpm[e] = i

INF = 10**9+1
ps = []
for i in range(Q):
    t, x = readline().split(); x = int(x)
    if t == 'ADD':
        y = R[x-1]
        if D[y] == 0:
            z = mp[y]
            idx = bisect(ps, z-1)
            ps = ps[:idx] + [z] + ps[idx:]
        D[y] += 1
    elif t == 'REMOVE':
        y = R[x-1]
        D[y] -= 1
        if D[y] == 0:
            z = mp[y]
            idx = bisect(ps, z-1)
            ps.pop(idx)
    else:
        left = -1; right = INF
        while left+1 < right:
            mid = (left + right) >> 1
            prv = -1
            cnt = 0
            for e in ps:
                s = S[e]; v = mpm[s]
                idx = max(bisect(T, s-mid-1)-1, prv)
                cnt += v - idx
                prv = v
            if N - cnt <= x:
                right = mid
            else:
                left = mid
        if right == INF:
            write("NA\n")
        else:
            write("%d\n" % right)