URL:https://www.luogu.org/problem/P3391
質問の意味:
列数は、$ a_iを=私はすべての反転出力し、その結果をフリップメンテナンス間隔の列の数を$。
ソリューション:
、treapソリューション:
セクションでの$ treapの$ソリューションをひっくり返し関与するだけirrotationality $ treap $使用することができ、そこに右の三つのサブツリーに何のスピンの$ treapの$分割、セクション間に残さすなわち間隔になることはありませその後、セクションに切り替えますして、マークされたサブツリーをマーク$による$マージ$ときなし他のサブツリーマークの横パスなので、$スプリット$をし、彼らはまた、最初にマークして、$スプリット$の下を通過、次に$とき、パスマークをマージします。私達はちょうど予約限定!最後に、それは出力の結果であるように、ツリートラバーサル順序どおり出力バランスは、元のシーケンスでなければなりません。
ACコード:
#include <ビット/ STDC ++ H> 名前空間STDを使用して、 const int型MAXN = 1E5 + 5。 Treapのstruct { int型のval [MAXN]、息子[MAXN] [2]、RNK [MAXN]、サイズ[MAXN]。 BOOLタグ[MAXN]。 SZをint型。 INITを無効() { SZ = 0。 } ボイド押し上げ(INT X) { サイズ[X] =サイズ[息子[X] [0] +サイズ[息子[X] [1]] + 1。 } ボイドプッシュダウン(INT X) { IF(タグ[X]) { タグ[X] = 0; タグ[息子[X] [0]] ^ = 1; タグ[息子[X] [1] ^ = 1; スワップ(息子[X] [0]、息子[X] [1])。 } } int型_rand() { 静的INTシード= 12345。 戻りシード= INT(シード* 482711ll%2147483647)。 } ボイドマージ(INT&RT、INT A、INT B) { IF(|| B!) { RT = A + B。 返します。 } (RNKは[A] <RNK [B])であれば { プッシュダウン(A)、RT =。 マージ(息子[RT] [1]、息子[A] [1]、B)。 } 他 { プッシュダウン(B)、RT = B。 マージ(息子[RT] [0]、息子[B] [0])。 } 押し上げ(RT)。 } ボイドsplit_sz(INT RT、INT&A、INT&B、int型の) { IF(RT == 0) { A = B = 0。 返します。 } プッシュダウン(RT)。 IF(サイズ[息子[RT] [0] <S) { =のRT。 split_sz(息子[RT] [1]、息子[A] [1]、B、S -サイズ[息子[A] [0]] - 1)。 } 他 { B = RT。 split_sz(息子[RT] [0]、息子[B] [0]、S)。 } 押し上げ(RT)。 } ボイドsplit_v(INT RT、INT&A、INT&B、int型V) { IF(RT == 0) { A = B = 0。 返します。 } プッシュダウン(RT)。 IF(ヴァル[A] <= V) 、A = RT、split_v(息子[RT] [1]、息子[A] [1]、B、V)。 他 B = RT、split_v(息子[RT] [0]、息子[B] [0]、V)。 突き上げ(RT)。 } INT newnode(INT X) { int型RT = ++ SZ。 ヴァル[RT] = xと; RNK [RT] = _rand()。 息子[RT] [0] =息子[RT] [1] = 0; サイズ[RT] = 1。 タグ[RT] = 0; RTを返します。 } ボイドインサート(INT&RT、INT V) { int型、X = 0、Y = 0、N = newnode(V)。 split_v(RT、X、Y、V)。 (X、X、n)と合流。 (RT、x、y)をマージ。 } ボイドrerverse(INT&RT、int型のL、R INT) { int型、X = 0、Y = 0、Z = 0。 split_sz(RT、X、Y、R)。 split_sz(X、X、Z、L - 1)。 タグ[Z] ^ = 1; (X、X、Z)マージ。 (RT、x、y)をマージ。 } ボイドプリント(INT RT) { プッシュダウン(RT)。 IF(息子[RT] [0]) 、印刷(息子[RT] [0])。 のprintf( "%dの"、ヴァル[RT])。 IF(息子[RT] [1]) プリント(息子[RT] [1])。 } }。 TreapのTR; int型のp = 0; INTメイン() { tr.init()。 N INT、M。 scanf関数( "%d個の%のD"、&N、&M)。 (I 1 = int型I ++; iが<= n)のため tr.insert(P、I)。 int型のL、R。 (I 1 = int型; I <= M; ++ i)について { scanf関数( "%dの%のD"、&L&R)。 tr.rerverse(P、L、R)。 } tr.print(P)。 putchar( '\ n')で。 0を返します。 }
二、スプレイソリューション:
$ $スプレイその後、マーキング、解決策は、彼の息子の$ルートの右側にルートの$ $スプレイ、後輪駆動の$スプレイに右のポイントを前駆体の左端ポイントを置くために、息子は明らかに範囲を反転するには、左側の必要性のルートですができスプレイときに最初のマークとその下に、次にフリップパス、$ treap $と出力方法。
ACコード:
// luogu-判定部イネーブル-O2 の#include <ビット/ STDC ++ H> 名前空間STDを使用して、 const int型MAXN = 1E5 + 5。 構造体スプレイ { int型のサイズ[MAXN]、ヴァル[MAXN]、FA [MAXN]。 int型NUM [MAXN]、息子[MAXN] [2]、STA [MAXN]。 BOOLタグ[MAXN]。 int型SZ、室温; INIT()を無効 { RT = SZ = 0。 } アップボイド(INT X) { IF(X) { サイズ[X] = NUM [X]。 IF(息子[X] [0]) サイズ[X] + =サイズ[息子[X] [0]]。 IF(息子[X] [1]) サイズ[X] + =サイズ[息子[X] [1]。 } } (INT X)ダウンボイド { (タグ[X])であれば { タグ[X] = 0; タグ[息子[X] [0]] ^ = 1; タグ[息子[X] [1] ^ = 1; スワップ(息子[X] [0]、息子[X] [1])。 } } ボイドCON(int型のx、int型のY、INT zを) { IF(X) FA [X] = Y。 (Y)であれば 息子[Y] [Z] = xと; } INT getson(INT X) { 戻り息子[FA [X]] [1] == X。 } ボイド回転(INT X) { int型のFX = FA [X]、FFX = FA [FX]。 INT FS = getson(x)は、FFS = getson(FX)。 CON(息子[X] [FS ^ 1]、FX、FS)。 CON(FX、X、FS ^ 1)。 CON(X、FFX、FFS)。 アップアップ(FX)、(X)。 } ボイドスプレイ(int型のx、int型エンド) { 端= FA [END]。 int型のトップ= 0; (INT F = xと; F; F = FA [F])のための STA [++トップ]はFを=。 (I =トップint型; I; --I)のために ダウン(STA [I])。 int型F; 一方(FA [X] =終了!) { F = FA [X]。 (!FAは[F] =末端)場合に 回転する(?getson(X)== getson(F)F:X)。 (x)は、回転、 } (エンド!)の場合 = xを室温。 } INT newnode(int型のx、int型F) { int型のルート= ++ SZ。 ヴァル[ルート] = xと; サイズ[ルート] NUM [ルート] = 1 =。 息子[ルート] [0] =息子[ルート] [1] = 0。 FA [ルート] = F。 息子[F] [X>ヴァル[] F] =根。 タグ[ルート] = 0; ルートを返します。 } ボイド挿入(int型X) { IF(!RT) { RT = newnode(X、0); 返します。 } intは今= RT、F = 0。 一方、(1) { IF(X ==ヴァル[今]) { ++ NUM [今]。 アップ(今)、アップ(F); スプレイ(今、RT)。 返します。 } F =今、今=息子[今] [X>ヴァル[今]。 もし(今!) { int型TMP = newnode(X、F)。 (F)まで。 スプレイ(TMP、RT)。 返します。 } } } int型querynum(INT RNK) { int型ANS = 0、今RTは=。 一方、(1) { ダウン(今)。 ([[0]息子[今] [0] && RNK <=サイズ息子[今])場合 { 今=息子[今] [0]。 持続する; } IF(息子[今] [0]) RNK - =サイズ[息子[今] [0]]。 IF(RNK <= NUM [今]) { スプレイ(今、RT)。 今すぐ返します。 } RNK - = NUM [今]。 今=息子[今] [1]; } } ボイド逆(INT QL、QR INT) { int型のLが= querynum(QL)、R = querynum(QR + 2)。 スプレイ(L、RT)、スプレイ(R、息子[L] [1])。 タグ[息子[R] [0]] ^ = 1; } ボイドプリント(int型のx、int型N) { ダウン(X)。 (息子[X] [0])であれば 、印刷(息子[X] [0]、N)。 IF(ヴァル[X]> 1 &&ヴァル[X] <N + 2) のprintf( "%dの"、ヴァル[X] - 1)。 (息子[X] [1])であれば 、印刷(息子[X] [1]、N)。 } }。 スプレイSP; INTのmain() { int型N、M。 scanf関数( "%d個の%のD"、&N、&M)。 以下のために(INT i = 1; iが<= N + 2; ++ I) sp.insert(I)。 int型のL、R。 以下のために(; iがmを<; I = 0 int型++ I) { scanf関数( "%d個の%のD"、&L&R)。 sp.reverse(L、R)。 } sp.print(sp.rt、N)。 printf( "\ n")を。 0を返します。 }