羅区P3391文学バランスの取れたツリーtreapまたはスプレイ

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を返します。
}

  

おすすめ

転載: www.cnblogs.com/Aya-Uchida/p/11566735.html