CF809D

グッド魔法のデータ構造うん...

まず、我々は考える:暴力はどうすればよいですか?

範囲の限界位置は$ J $ $ [L、R] $である場合、状態$のDPをリセットする[J] $ $ J $が最後の数最小のシーケンス番号の長さを示し、は、明らかに転移。

$ DP [J] = L(DP [J-1] <L)$

$ DP [j]はDPを= [J-1] +1(L \当量DP [J-1] \当量のR-1)$

$ DP [J] = DP [J](DP [J-1] \ GEQ R)$

明らかに正し

最適化を考えてみましょう:私たちは、上記の3つの操作の物質を考慮してください。

最初の転送方向:前駆体の後ろにL $ $ $ L $を挿入します

二次転写方向:間隔の$ [Lを、R-1〕$プラス全体、右のセルの後に(後方にずれた位置に対応します)

第3の転送方向:削除の$ $のR&LT後継

そして、バランスの取れたツリーを使用して直接、考慮に挿入作業を取るたびに、上記の3つの操作を実装することができますので、右の第2の操作は、単に追加するという本当の事実を必要としません。

強くfhq_treapを達成することをお勧めします

コード:

書式#include <cstdioを> 
する#include <cmath> 
の#include <CStringの> 
の#include <cstdlib> 
書式#include <iostreamの> 
の#include <アルゴリズム> 
書式#include <キュー> 
の#include <スタック> 
の#include <ctimeの>
 に#define LSツリー[ RT] .lson
 の#define RSツリー[RT] .rson
 使用して 名前空間はstdを、
構造体FHQ_TREAP 
{ 
    int型LSON、rson。
    int型のSIZ。
    int型のval、ランク;
    int型怠惰; 
}ツリー[ 300005 ]。
int型 TOT =0 ;
int型の腐敗、再、N。
ボイド押し上げ(INT RT)
{ 
    ツリー[RT] .siz =ツリー[LS] .siz +ツリー[RS] .siz + 1 
} 
無効プッシュダウン(int型RT)
{ 
    場合(!RT)のリターン;
    もし(LS)ツリー[LS] .lazy + =ツリー[RT] .lazy、ツリー[LS] .val + = ツリー[RT] .lazy。
    もし(RS)ツリー[RS] .val + =ツリー[RT] .lazy、ツリー[RS] .lazy + = ツリー[RT] .lazy。
    ツリー[RT] .lazy = 0 
} 
INT new_node(INT V)
{ 
    int型 RET = ++TOT; 
    ツリー[RET] .siz = 1、ツリー[RET] .val = V、ツリー[RET] .rank = ランド()。
    リターンRET; 
} 
INTマージ(int型のx、int型Y)
{ 
    場合(!(X)||(Y))リターン X | Y;
    もし(ツリー[X] .lazy)プッシュダウン(X)。
    もし(ツリー[Y] .lazy)プッシュダウン(Y)。
    もし(ツリー[X] .rank < ツリー[Y] .rank)
    { 
        ツリー[X] .rson = (ツリー[X] .rson、y)をマージします。
        突き上げ(X)。
        リターンのx; 
    } 
    { 
        ツリー[Y] .lson= (X、ツリー[Y] .lson)をマージします。
        突き上げ(Y)。
        返すyと。
    } 
} 
ボイド分割(INT RT、INT K、INT&X、INTY)
{ 
    場合(RT!){X = Y = 0返す;}
     もし(ツリー[RT] .lazy)プッシュダウン(RT)。
    もし(ツリー[RT] .val <= K)X = RT、スプリット(RS、K、RS、Y)。
    そうでなければ、Y = RT、スプリット(LS、K、X、LS)。
    突き上げ(RT)。
} 
ボイドイン(INT V)
{ 
    int型X、Y。
    スプリット(腐敗、V、X、Y)。
    腐敗 =マージ((X、new_node(V))、Yマージ)。
} 
無効デル(INT V)
{ 
    int型X、Y、Z、W。
    スプリット(腐敗、V、X、Y)。
    スプリット(X、V - 1 、Z、W)。
    W = (.lson、ツリー[W] .rson [W]ツリー)をマージします。
    腐敗 = (W Y)、(Zマージ)マージ。
} 
ボイド更新(int型 RT、int型の L、INT R)
{ 
    int型X、Y、Z、W。
    スプリット(腐敗、L - 1 、X、Y)
    スプリット(Y、R、Z、W)。
    もし(Z)ツリー[Z] .lazy ++、ツリー[Z] .val ++ 
    腐敗 =マージ(X(Z、W)をマージ)。
} 
無効 get_pro(int型 RT、int型V)
{ 
    場合(!RT)のリターン;
    場合(V <= ツリー[RT] .val)get_pro(LS、V)。
    再= ツリー[RT] .val、get_pro(RS、V)。
} 
INT get_minn(INT RT)
{ 
    場合(LS!)戻りツリー[RT] .val。
    他の リターンget_minn(LS); 
} 
INT get_sub(INT V)
{ 
    int型X、Y。
    スプリット(腐敗、V、X、Y)。
    int型 RET =get_minn(Y)。
    腐敗 = (x、y)をマージします。
    リターンRET; 
} 
インラインint型リード()
{ 
    int型、F = 1、X = 0チャー CH = GETCHAR()。
    一方、(CH < ' 0 ' || CH> ' 9 '){ 場合(CH == ' - ')、F = - 1 ; CH = GETCHAR();}
     一方(CH> = ' 0 ' && CH <= ' 9 '){X = X * 10CH- +
        イン(L)。' 0 ' ; CH = GETCHAR();}
     戻りのx *のF。
} 
ボイド)(解く
{ 
    srand関数(時間(NULL))。
    N = 読み取ります();
    以下のためにint型 i = 1 ; iが<= N; iは++ 
    { 
        int型 L =読み取る()、R = 読み取り()。
        もし(I == 1){イン(L)。引き続き;}  = get_sub(R- 1 )。
        アップデート(腐敗、L、R - 1 )。
        もし(再)デル(再)。
    }
    場合(!腐れ病)のprintf(" 0 \ nを" );
    のprintf(" %d個の\ n " 、ツリー[腐敗] .siz)。
} 
int型のmain()
{ 
    )(解きます。
    リターン 0 ; 
}

 

おすすめ

転載: www.cnblogs.com/zhangleo/p/11101131.html