BZOJ 4771:カラフルなツリー永続鎖セグメントの木と木+

このアイデアは非常に興味深いです -     

ツリー・チェーンを使用して一度だけ各色の寄与を確認し、その後、持続セグメント・ツリーのメンテナンスであること 

コード: 

#include <セット> 
の#include <cstdioを> 
する#include <CStringの>    
する#include <アルゴリズム>      
の#define N 100005    
の#define setIO(S)freopenは(S ".IN"、 "R"、標準入力)、(S freopenは」。アウト」、 『』ワット、STDOUT)     
名前空間stdを使用。
名前空間SEG 
{    
    に#define LSON T [X] .ls 
    の#define rson T [X] .RS 
    INT TOT。   
    構造体ノード
    { 
        int型LS、RS、合計。
    } T [N * 80]。        
    ボイドCLR()
    { 
        用(INT iは= 1; I <= TOT; ++ I)T [i]は.ls = T [i]を.RS = T [i]が.SUM = 0。
        TOT = 0;    
    } 
    INT newnode()
    { 
        リターン++ TOT。
    ボイドビルド(INT&X、INT L、int型R)
    {    
        X = newnode()。
        (L == R)戻った場合。
        INTミッド=(L + R)>> 1。   
        ビルド(LSON、L、ミッド)(L <= MID)の場合。
        IF(R> MID)ビルド(rson、ミッド+ 1、R)。   
    } 
    int型のCOP(int型のx、int型のL、R INT、INT P、INT V)
    { 
        int型今= newnode()。
        T [今] = T [X]。   
        T [今] .SUM + = V。     
        (L == R)は今戻った場合。
        INTミッド=(L + R)>> 1。   
        IF(p <= MID)T [今] .ls = COP(LSON、L、中、P、V)。
        他T [今] .RS = COP(rson、ミッド+ 1、R、P、V)。    
        今すぐ返します。      
    } 
    INTクエリ(int型のx、int型、L、R INT、INT L、int型R)
    {    
        (!X)であれば0を返します。
        IF(L> = L && R <= R)戻りT [X] .SUM。
        int型の再= 0;  
        INTミッド=(L + R)>> 1。
        (L <= MID)再+ =クエリ(LSON、L、中、L、R)であれば、
        IF(R> MID)再+ =クエリ(rson、ミッド+ 1、R、L、R)。
        再を返します。
    }        
    の#undef LSON 
    の#undef rson 
}。  
セット<整数> SE [N]。   
セット<整数> ::イテレータFR、BA;     
INTエッジ、N、M、ティム、CT。        
INT HDに[N]、[N]、NEX [N]、COL [N]、NOD [N]、ST [N]、ED [N]。           
FA INT [N]、DFN [N]、DEP [N]、サイズ[N]、息子[N]、トップ[N]。       
INT ID [N]、RT [N]。   
ブールCMP(int型B、INT)
{ 
    戻りDEP [A] <DEP [B]。   
}
ボイド追加(INT U、V INT)
{ 
    NEX [++エッジ] = HD [U]、[エッジ] = VにHD [U] =エッジ;  
} 
ボイドDFS1(INT U、INT FF)
{      
    サイズ[U] = 1。   
    DFN [U] = ++ティム。
    ST [U] = DFN [U]。    
    NOD [DFN [U] = U。     
    DEP [U] = DEP [FF] +1。   
    (; iはNEX [I] = [U] INT I = HD)用
    { 
        int型V =に[I]を、  
        DFS1(V、U);   
        サイズ[U] + =サイズ[V]。  
        IF(サイズ[V]>サイズ[息子[U])息子[U] = V。   
    } 
    ED [U] =ティム。   
} 
ボイドDFS2(INT U、INT TP)
{ 
    トップ[U] = TP。
    IF(息子[U])DFS2(息子[U]、TP)。
    (; iはNEX [I]を= [U] INT I = HD)用
    {
        IF(の[I] =息子[U]!)
        { 
            DFS2([I]に、[I]に);   
        } 
    } 
} 
int型LCA(int型のx、int型のY)
{ 
    一方(上面[X]!= TOP [Y])
    { 
        DEP [トップ[X]]> DEP [トップ[Y]]?X = FA [トップ[X ] Y = FA [トップ[Y]。
    } 
    戻りDEP [X] <DEP [Y] X:Y;?   
} 
ボイド解く()
{     
    = 0最後INT I、J、。
    scanf関数( "%D%D"、&N、&M)。               
    ための式(I = 1; I <= N; ++ I)のscanf( "%d個"、&COL [I])。
    以下のために(I 2 =、iが<= N; ++ I)   
    { 
        scanf関数( "%d個"、&FA [I])。
        追加(FA [i]は、I)。          
    } 
    DFS1(1,0)。   
    DFS2(1,1)。           
    ため(I 1 =、iが<= N; ++ I)のID [I] = I。  
    ソート(ID + 1、ID + 1 + N、CMP)。         
    int型LST = 0;   
    SEG ::ビルド(RT [0]、1、N)   
    (++ I; I <= n iは= 1)のための
    {                
        INT P = ID [i]は、
        INT C = COL [P]。             
        一方、(DEP [P]> LST)RT [LST + 1] = RT [LST] ++ LST。                  
        SE [C] .insert(DFN [P])。   
        FR = BA = SE [C] .lower_bound(DFN [P])、BA ++。            
        IF(FR = SE [C] .begin()!)
        {   
            --fr。   
            RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* FR]、P)] - 1)。   
            ++ FR;    
        } 
        IF(BA!= SE [C] .END())
        {
            RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* BA]、P)] - 1)。  
        } 
        (FR = SE [C] .begin()&& BA = SE [C] .END()!)であれば
        { 
            --fr。     
            RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [LCA(NOD [* FR]、NOD [* BA)]、1)。    
        }                    
        RT [LST] = SEG :: COP(RT [LST]、1、nは、DFN [P]、1)。             
    }     
    (iは= 1; I <= M; ++ i)に対する
    { 
        int型のx、D。
        scanf関数( "%D%D"、およびX、&D)。     
        X ^ =最後、D ^ =最後。        
        最後= SEG ::クエリ(RT [分(N、DEP [X] + D)]、1、nは、ST [x]は、ED [X])。  
        printf( "%d個\ n"は、最後の);           
    }         
    (iは= 1; I <= N; ++ i)に対する息子[I] = 0;  
    (iは= 1; I <= N; ++ i)に対するHD [I] = 0;
    ための式(I = 1; I <=縁; ++ I)NEX [I] =に[I] = 0;     
    エッジ=ティム= 0。
    ワンセグ:: CLR(); 
    SE [I] .clear()(iは++; <I = N I = 1の)のため;        
} 
int型のmain()
{ 
    // setIO( "入力")。
    I、J、Tをint型。
    scanf関数( "%のD"、&T)。
    一方、(T--)(解きます)。  
    0を返します。
}

  

おすすめ

転載: www.cnblogs.com/guangheli/p/12049581.html
おすすめ