質問が意図されている:あなたの長さnの文字列を与えるために、m回は、k番目の元の文字列で発生するサブ問合せL rの位置にその都度求め-1ない出力場合があります。N、Mは1E5レベルです。
アイデアは:接尾辞配列は、この質問にはかなりのミスを学んだ限り、実際には、接尾辞配列のQAQを学ぶない後悔します。この問題は、サフィックスの数に変換することが可能とサフィックスLCP長Lは以上でRは - L + 1。我々は、接尾辞配列では、2つの添え字i、jは、LCPの分(高さ[順位[J] + 1]、高さ[順位[J] + 2]、...高さである、ことを知っている[順位[I] )。ランク付けするPからL + 1、すなわち、[L]これらの場所 - ので、我々は、2つの(この位置はPであると仮定して)ほとんどの位置を左に分離することができ、ランク[L]の位置は、高さ> = RでありますサフィックスとLCPは、以上の長さL rは - L + 1です。右ランク[L]は同様にして得ることができます。だから、私たちはその答えであるかもしれないものの接尾辞を知ることができます。そして、問題は、彼らがそれk番目の位置にある知っていますか、ありますか?これは大きな問題のK-静的な範囲で、我々は[i]は会長ツリーを挿入し、K-大きなポジションを依頼するために、分離された二つのエンドポイント間で二分することができますsaの。
コード(接尾辞配列ボードのコピーをオンラインQAQ):
#include <ビット/ STDC ++ H> 名前空間STDを使用して、 const int型MAXN = 100010; チャーS [MAXN]。 int型nは、TOT; int型のルート[MAXN]。 構造体ノード{ int型の合計。 int型のLC、RC。 }。 ノードTR [MAXN * 50]。 構造体SA { INT SA [MAXN]、X [MAXN]、Y [MAXN]、[MAXN] C。 INTランク[MAXN]、高さ[MAXN]、H [MAXN]。 【MAXN] F INT [18]。 ボイドbuild_sa(int型M){ [I] = 0 C(; I <= M I ++は、I = 0をINT)ため、 以下のために(INT I = 1; I <= N; ++ I)、C ++ [X [I] = sの[I]]。 // C数组是桶 // X [i]は是第I个元素的第一关键字 (I = 2をint型、I <= M; ++ i)に対するC [I] + = C [I-1] ; //プレフィックスおよびcは、我々は各キーワードに描くことができないいくつかの最初のものです 以下のために(INT I = N; I> = 1; --I)SA [Cの[X [I]] - ] = I。 のため(。。INT 1 = K、K <= N - 、= K << 1){ = 0 INT NUMは、 (。; I <= N - 、I = N-K- + int型1私++)のためにY [NUM ++] = I; // Y [i]は、iの2番目のキーワード順位番号を表します。最初のキーワードの位置に 第二のキーワードに// n番目ビットのN-K + 1が前列に、したがってない (; iがi = 1をint型のための (SA場合、<= N ++ i)を[I]> k)をY [NUM ++] = SA [i]の-k; // iはk番目のビットの後ことランキング配列の数であり //条件式(SA [I]> k)は、それ他の人は、線yに最初に追加されたキーワードの位置に入れて、2番目のキーとして使用することができます ので、私の列挙は、第2の鍵、最初のチームの前に、第2の鍵である// のための(INT 1 = I; I <= M、Iが++)C [I] = 0; // C槽を初期化する (; iは1 = int型のため = N <; ++ I)、C ++ [X [I ]; //最初のキーワードを直接リストに追加するように周期が算出された前回ので ため(INT I = 2; I <= M; ++ I)のC [I] + = C [1- 1]; //最初のキーワードはどのように多くの私の数に1をランク付け SA [C [X [Y [I]]] - ] = Y [I]、Y [I]は= 0(。;私は> = 1社(www.i-levelmedia.com)INT I = N-);ため 2番目のキーワードの順序がに従ってため// yは注文行 バケット順同じ最初のキーワードに、後方に第二キーワード//後 //基数ソート スワップ( X、Y); //は、新しいxは、古いを使用するために生成されるので、あまりにも多くあると思いません、ダウン古いコピーを入れて、他の意味はありません X [SA [1] = 1; NUM = 1 ; (; I <= N-I ++のI = 2 INT)用 X [SA [I] =(Y [SA [I]] == Y && Y [SA [I [SA [-I 1]。] ] + K] Y - == [SA [I-1] + K])NUM :? NUM ++; [i]のSAがすでにソートされている//ので、評価の列挙、次の世代のことですることができますので、キーワード IF(== N-NUM)BREAK; M = NUM; //ここでそのない122、新規の数があるので } } ボイドget_height(){ int型K = 0; 。ため(INT I = 1 ;私は<= N-; Iはランク[SA [I] = I)++ のための(INT I = 1; I <= N - 、Iは++します){ IF(ランク[I] == 1)継続; //第一名高さは为0 (K)IF - K; // H [I]が> = Hの[1-I] -1; INT J = SA [順位[I] -1]。 ながら(J + K <= N && I + K <= N && S [I + K] == S [J + K] )++、K。 高さ[順位[I] = K; // H [i]は=高さ[RK [i]は]。 } (i = 1をint型、iが<= N; iが++)のためにH [I] =高さ[順位[i]は]。 } ボイドbuild_st(){ ため(; iがn = <; I = 1 int型私は++) F [i]が[0] =高さ[I]。 INT、T =ログ(N)/ログ(2)+ 1。 用(INTのJ = 1; J <T、J ++){ ため(; iがn = < - (1 << J)+ 1; iは1 = int型私は++) [I] [J] =分(F [I F ] [J - 1]、iは(1 <<(j - 1))+ [F] [J - 1])。 } } int型クエリ(int型のL、R INT){ IF(L> R)戻り0; int型K =ログ(R - L + 1)/ログ(2)。 戻り分(F [L] [K]、F [R - (1 << } }。 SAは解決します。 INTビルド(int型L、int型R){ int型、P = ++ TOT。 IF(L == R){ TR [P] .SUM = 0。 TR [P]を得た。LC = TR [P] .RC = 0。 Pを返します。 } INT半ば=(L + R)>> 1。 TR [P]を得た。LC =ビルド(L、MID)。 TR [P] .RC =ビルド(MID + 1、R)。 TR [P] .SUM = TR [TR [P]を得た。LC] .SUM + T R [TR [P] .RC] .SUM。 Pを返します。 } int型インサート(INTは今、int型のL、int型のR、int型のx、int型のval){ int型のP = ++ TOT。 TR [P] = TR [今]。 IF(L == R){ TR [P] .SUM = 1。 Pを返します。 } INT半ば=(L + R)>> 1。 IF(X <= MID)TR [P]を得た。LC =(TR [今]を得た。LC、L、中、X、ヴァル)を挿入します。 他のTR [P] .RC =インサート(TR [今] .RC、中間+ 1、R、X、ヴァル)。 TR [P] .SUM = TR [TR [P]を得た。LC] .SUM + T R [TR [P] .RC] .SUM。 Pを返します。 } INTクエリ(INT lnow、INT rnow、INT L、のint R、intは残る){ IF(L> R)戻り0; IF(L == R){ 戻りL。 } INT半ば=(L + R)>> 1。 INT TMP = TR .SUM [rnow]を得た。LC TR] - T R [TR [lnow]を得た。LC] .SUM。 IF(TMP> =が残って)リターンクエリ(TR [lnow]を得た。LC、[rnow]を得た。LC、L、中間TR、残ります)。 他戻りクエリ(TR [lnow] .RC、TR [rnow] .RC、中間+ 1、R、残る- TMP)。 } {main()のint型 T、M、L、R、K、QL、QRをint型。 // freopenは( "cin.txt"、 "R"、STDIN)。 // freopenは( "cout.txt"、 "W"、STDOUT)。 一方、(T--){ TOT = 0。 scanf関数( "%d個の%のD"、&N、&M)。 scanf関数( "%sの"、S + 1)。 ための式(I ++はint型i = 1; iが<= n)が S [I] - =( '' - 1)。 solve.build_sa(30)。 solve.get_height(); solve.build_st(); ルート[0] =ビルド(1、N) (I 1 = int型、iが<= N; iが++)のために{ ルート[I] =(根[I - 1]、1、nは、solve.sa [i]は、1)を挿入します。 } ため(INT I = 1; I <= M; iは++){ 他のR =ミッド; のscanf( "%D%D%D"、&L&R&K)を、 int型のp =解きます。 INTはL = 1、R = P。 (L <R){一方 INT半ば=(L + R)>> 1。 IF(solve.query(MID + 1、P)<R - L + 1)L =ミッド+ 1。 QL = L; L = P、R = N。 一方、(L <R){ int型ミッド=(L + R + 1)>> 1。 IF(solve.query(P + 1、MID)<R - L + 1)R =ミッド- 1。 他のL =ミッド; } QR = R。 IF(QR - QL + 1 <K)のprintf( " - 1 \ n"); 他のprintf( "%Dを\ n"、クエリ(ルート[QL - 1]、根[QR]、1、N、K))。 } } }