주제 링크 : http://poj.org/problem?id=2104
타이틀 효과 :뿐만 아니라 주어진 N의 시퀀스 번호 m 조작, L, R, K를 포함하는 각 동작 구간 발견 [L을 R] k 번째로 큰
문제 해결 방안은 : 최대 세그먼트 트리는 최소 서열을 유지 트리 라인의 N 개의 포함 된 각 입력 시퀀스 접두어 세그먼트 트리의 구축을 고려할 수 있고, 이것은 확실히 메모리 버스트 것이다. 같은 나무의 두 인접 분절 사실, 아마 로그 n 개의 노드, 우리는 거기에 새 로그 n 개의 노드를 열어 다른 많은있다. 현재의 노드 번호의 각각의 합계가 저장된 노드 번호 우리 세그먼트 트리의 L-1 개를 얻는다 제 세그먼트 트리 감산을 사용하여 간격 [L, R, R 피스 [L, R] 간격으로 나타나는 각 노드가 자신의 좌측 서브 트리에서 시작하여 나타나는 횟수 이상인 K 왼쪽 서브 K에 큰 나무를 찾는 경우에, 좌측 서브 트리의 노드 번호 K에 동일 합보다 큰지 여부를 판단하거나 상기 제 우측 서브 트리를 찾는 검색 시작 케이 합 대형.
코드 :
사용법 #include <iostream> #INCLUDE <알고리즘> #INCLUDE <벡터> #INCLUDE <cstdio> 사용 스페이스 성병; CONST의 INT maxn 1E5 + = 6 ; INT의 N, m, CNT 루트 [maxn], A [maxn, X, Y, K; 구조체 노드 { INT의 L, R, 합; } T [maxn * 40 ]; 벡터 < INT > V; INT getid ( INT X) { 복귀 LOWER_BOUND (v.begin () v.end (), X) -v.begin () + 1 ; } 무효 업데이트 ( INTL, INT R, INT 및 X, INT의 Y, INT의 POS) { T [ ++ CNT = T [Y], T [CNT] .sum ++ , X = CNT; 경우 (L == R) 창 ; int로 중간 = L + R >> 1 ; 경우 (MID> = POS) 업데이트 (좌, 중, T [X] 펜닐, T [Y] 펜닐, POS); 다른 업데이트 (MID + 1 , R, T [X] .R, T [Y] .R, POS); } INT의 쿼리 ( INT의 L, INT의 R, INT (X), INT의 Y, INT의 K) { 경우 (L == R) 창엘; int로 중간 = L + R >> 1 ; INT의 합 = T [T [Y] 펜닐] .sum- T [T [X] 펜닐] .sum; 경우 (합계> = K) 리턴 질의 (좌, 중, T [X] 펜닐, T [Y] 펜닐, K); 다른 리턴 질의 (MID + 1 , R, T [X] .R, T [Y] .R, K- 합); } INT 의 main () { 는 scanf ( " %의 D % d에 " , N, m); 위한 ( int로 I = 1 ; 나는 <= N; ++ i가 ()는 scanf를 " 가 % d " , & A [I]) v.push_back (a [I]); 종류 (v.begin (), v.end ()), v.erase (독특한 (v.begin (), v.end ()), v.end ()); 위한 ( int로 I = 1 ; 나는 <= N; 내가 ++) 업데이트 ( 1 N, 루트 [I], 루트 [I- 1 ] getid (a [I])); 위한 ( int로 난 = 1 난 ++; I <= m {) 는 scanf ( " % D % D % D ' , X, Y, K)을; 의 printf ( " % D \ 없음 " , V [질의 ( 1 N, 루트 [X- 1 ], 루트 [Y, K) - 1 ]); } 반환 0 ; }