結果

問題 No.3167 [Cherry 7th Tune C] Cut in Queue
ユーザー 👑 Kazun
提出日時 2023-11-19 22:51:53
言語 PyPy3
(7.3.15)
結果
RE  
実行時間 -
コード長 8,060 bytes
コンパイル時間 401 ms
コンパイル使用メモリ 82,704 KB
実行使用メモリ 251,156 KB
最終ジャッジ日時 2025-05-30 21:02:51
合計ジャッジ時間 18,565 ms
ジャッジサーバーID
(参考情報)
judge2 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample RE * 2
other RE * 43
権限があれば一括ダウンロードができます

ソースコード

diff #

class Doubly_Linked_List:
    def __init__(self, N):
        self.__N=N
        self.__front=[-1]*N
        self.__back=[-1]*N

    def __len__(self):
        return self.__N

    def __str__(self):
        res=[]
        used=[0]*self.__N

        for x in range(self.__N):
            if used[x]:
                continue

            a=self.enumerate(x)
            for y in a:
                used[y]=1
            res.append(a)
        return str(res)

    def __repr__(self):
        return "[Doubly Linked List]: "+str(self)

    def previous(self, x, default=-1):
        return self.__front[x] if self.__front[x]!=-1 else default

    def next(self, x, default=-1):
        return self.__back[x] if self.__back[x]!=-1 else default

    def disconnect_front(self, x):
        """ x から前に伸びるリンクを削除する.

        """

        front=self.__front; back=self.__back

        y=front[x]
        if y>=0:
            front[x]=-1
            back[y]=-1

    def disconnect_back(self, x):
        """ x から後ろに伸びるリンクを削除する.

        """

        front=self.__front; back=self.__back

        y=back[x]
        if y>=0:
            back[x]=-1
            front[y]=-1

    def extract(self, x):
        """ x に接続するリンクを削除し, x の前後が存在するならば, それらをつなぐ.
        """

        a=self.__front[x]
        b=self.__back[x]

        self.disconnect_front(x)
        self.disconnect_back(x)

        if a!=-1 and b!=-1:
            self.connect(a,b)

    def connect(self, x, y):
        """ x から y へのリンクを生成する (すでにある x からのリンクと y へのリンクは削除される).

        """

        self.disconnect_back(x)
        self.disconnect_front(y)
        self.__back[x]=y
        self.__front[y]=x

    def insert_front(self, x, y):
        """ x の前に y を挿入する.

        """

        z=self.__front[x]
        self.connect(y,x)
        if z!=-1:
            self.connect(z,y)

    def insert_back(self, x, y):
        """ x の後に y を挿入する.

        """

        z=self.__back[x]
        self.connect(x,y)
        if z!=-1:
            self.connect(y,z)

    def head(self, x):
        """ x が属する弱連結成分の先頭を求める.
        """

        while self.__front[x]!=-1:
            x=self.__front[x]
        return x

    def tail(self, x):
        """ x が属する弱連結成分の末尾を求める.
        """

        while self.__back[x]!=-1:
            x=self.__back[x]
        return x

    def enumerate(self, x):
        """ x が属している弱連結成分を先頭から順に出力する.

        """

        x=self.head(x)
        res=[x]
        while self.__back[x]>=0:
            x=self.__back[x]
            res.append(x)
        return res

    def depth(self, x):
        dep=0
        while self.__front[x]!=-1:
            x=self.__front[x]
            dep+=1
        return dep

class Binary_Indexed_Tree():
    def __init__(self, L, op, zero, neg):
        """ op を演算とする N 項の Binary Indexed Tree を作成
        op: 演算 (2変数関数, 可換群)
        zero: 群 op の単位元 (x+e=e+x=x を満たす e)
        neg : 群 op の逆元 (1変数関数, x+neg(x)=neg(x)+x=e をみたす neg(x))
        """
        self.op=op
        self.zero=zero
        self.neg=neg
        self.N=N=len(L)
        self.log=N.bit_length()-1

        X=[zero]*(N+1)

        for i in range(N):
            p=i+1
            X[p]=op(X[p],L[i])
            q=p+(p&(-p))
            if q<=N:
                X[q]=op(X[q], X[p])
        self.data=X

    def get(self, k):
        """ 第 k 要素の値を出力する.

        k    : 数列の要素
        index: 先頭の要素の番号
        """
        return self.sum(k, k)

    def add(self, k, x):
        """ 第 k 要素に x を加え, 更新を行う.

        k    : 数列の要素
        x    : 加える値
        """
        data=self.data; op=self.op
        p=k+1
        while p<=self.N:
            data[p]=op(self.data[p], x)
            p+=p&(-p)

    def update(self, k, x):
        """ 第 k 要素を x に変え, 更新を行う.

        k: 数列の要素
        x: 更新後の値
        """

        a=self.get(k)
        y=self.op(self.neg(a), x)

        self.add(k,y)

    def sum(self, l, r):
        """ 第 l 要素から第 r 要素までの総和を求める.
        ※ l != 0 を使うならば, 群でなくてはならない.
        l: 始まり
        r: 終わり
        """
        l=l+1 if 0<=l else 1
        r=r+1 if r<self.N else self.N

        if l>r:
            return self.zero
        elif l==1:
            return self.__section(r)
        else:
            return self.op(self.neg(self.__section(l-1)), self.__section(r))

    def __section(self, x):
        """ B[0]+...+B[x] を求める. """
        data=self.data; op=self.op
        S=self.zero
        while x>0:
            S=op(data[x], S)
            x-=x&(-x)
        return S

    def all_sum(self):
        return self.sum(0, self.N-1)

    def binary_search(self, cond):
        """ cond(B[0]+...+B[k]) が True となるような最小の k を返す.

        cond: 単調増加

        ※ cond(zero)=True の場合の返り値は -1 とする.
        ※ cond(B[0]+...+B[k]) なる k が (0<=k<N に) 存在しない場合の返り値は N とする.
        """

        if cond(self.zero):
            return -1

        j=0
        r=self.N
        t=1<<self.log
        data=self.data; op=self.op
        alpha=self.zero

        while t>0:
            if j+t<=self.N:
                beta=op(alpha, data[j+t])
                if not cond(beta):
                    alpha=beta
                    j+=t
            t>>=1

        return j

    def __getitem__(self, index):
        if isinstance(index, int):
            return self.get(index)
        else:
            return [self.get(t) for t in index]

    def __setitem__(self, index, val):
        self.update(index, val)

    def __iter__(self):
        for k in range(self.N):
            yield self.sum(k, k)

#==================================================
def solve():
    from operator import add, neg
    from collections import defaultdict

    N = int(input())
    A = [0] + list(map(int, input().split()))

    length = N
    Q = int(input())
    Query = []
    for _ in range(Q):
        q, *value = map(int, input().split())
        if q == 1:
            length += 1
        Query.append((q, *value))

    L = Doubly_Linked_List(length + 2)
    start = 0; goal = length + 1
    for i in range(1, N + 1):
        L.connect(i - 1, i)
    L.connect(N, goal)

    index = defaultdict(list)
    for i,a in enumerate(A[1:], 1):
        index[a].append(i)

    j = N
    for q, *value in Query:
        if q == 1:
            x, y = value

            if x != -1:
                i = index[x][-1]
            else:
                i = 0

            j += 1
            k = L.next(i)
            L.connect(i, j)
            L.connect(j, k)

            index[y].append(j)

    L_inv = [0] * (length + 2); ind = 0
    for k in range(length + 2):
        L_inv[ind] = k
        ind = L.next(ind)

    index_inv = {v: [L_inv[x] for x in index[v]][::-1] for v in index}

    B = Binary_Indexed_Tree([0] * (length + 2), add, 0, neg)
    for i, a in enumerate(A[1:], 1):
        B.add(index_inv[a][-1], a)

    ans = []
    for q, *value in Query:
        if q == 1:
            x, y = value
            B.add(index_inv[y][-1], y)
        elif q == 2:
            x, = value
            B.add(index_inv[x][-1], -x)
            index_inv[x].pop()
        else:
            x, y = value
            s = index_inv[x][-1]; t = index_inv[y][-1]
            l = min(s, t); r = max(s, t)
            ans.append(B.sum(l, r))

    return ans

#==================================================
import sys
input=sys.stdin.readline
write=sys.stdout.write

write("\n".join(map(str, solve())))
0