Luogu P3833 [SHOI2012]魔法の木

この問題の理論に対する最適解

トピックリンク

効果の件名:サブツリーを合計し、パスを変更します

明らかに、テンプレートツリーのセクションが、クロスの木の時間複雑アップ卓越した$ \シータ(Q \;ログイン ^ 2N)$、 実際に木の差が時間複雑$ \シータに置くことができます(Qを\; LOGN)$。

全ての値に設定$タグ[X] $ 1~ $ X $ $ $パスは、追加明らかに $(x、y)との$ Dの$このパスを追加操作$とみなすことができる
$$タグ[X] + = D、タグ[Y] + = D、タグ[LCA(X、Y)] - = D、タグ[PRT [LCA(X、Y)]] - = D $$

木と子の$ルート$ルートのクエリは、回答のサブツリー内の各点$ xには$の寄与を考慮した場合である
(DEP [X] -dep [$$ルート] +1)\回タグ[X] $ $の
式センスポイントは、すべて$タグが追加される(X、根)$パス$ある[X] $、加算したタイプの
$$ \和\を、((DEP [X] - DEP [ルート]さんが+1)\タイムズタグ[X])$$
$$ \ SUM \;(DEP [X] \タイムズタグ[X] - (DEP [ルート] -1)\タイムズタグ[X])$ $
$$ \ SUM \;(DEP [X] \タイムズタグ[X]) - (DEP [ルート] -1)\タイムズ\ SUM \;(タグ[X])$$

二フェンウィックツリーのメンテナンス$のDEP [X]回タグ\ [X] $と$タグ順序$ DFS $サブツリーに連続した範囲、直接クエリであるため、[X] $は、良いです。

私はあまりにも醜いコードが一定であるだから、理論的な最適解はツリーセクションとして良い実行する必要があります

#include <iostreamの> 
する#include <iomanip> 
の#include <CStringの> 
する#include <cstdioを> 
する#include <cmath> 
の#include <アルゴリズム>
 使用して 名前空間STDを、
#defineは長いlong int型
インラインint型(){読み取り
     チャーCH。
    BOOL BJ = 0 しばらく(!isdigit(CH = getchar関数()))
        BJ | =(CH == ' - ' );
    INT RES = CH ^(3 << 4 )。
    一方、(isdigit(CH =GETCHAR()))
        RES =(RES << 1)+(RES << 3)+(CH ^(3 << 4 ))。
    リターン?BJ - 解像度:解像度。
} 
ボイド printnum(INT X){
     場合(X> 9)printnum(X / 10 )。
    putchar(Xの10 + ' 0 ' )。
} 
インラインボイドプリント(INT X、チャーCH){
     場合(X < 0 ){ 
        のputchar(' - '); 
        X = - X。
    } 
    printnum(X)。
    putchar(CH)。
} 
のconst  int型 MAXN = 1E5 + 5 INTのN、M、H [MAXN]、CNT。
INT TOP [MAXN]、サイズ[MAXN]、PRT [MAXN]、息子[MAXN]、DEP [MAXN]、TOT、TID [MAXN]。
構造体のエッジ{
     INT 、NXTに、
} [MAXN W << 1 ]。
INT C1 [MAXN]、C2 [MAXN]。
インラインボイド AddEdge(int型のx、int型のY){ 
    [W = .nxt ++ CNT] H [X]。
    W [CNT] .TO = Y。
    H [X]= CNT。
} 
ボイド DFS1(int型のx、int型 FA、int型の深さ){ 
    DEP [X] = 深度。
    PRT [X] = FA。
    サイズ[X] = 1 以下のためにint型 I = hの[X]; I; I = W [i]は.nxt){
         int型、V = W [i]は.TO。
        もし(== FA V)続けます
        DFS1(V、X、深さ + 1 )。
        もし(サイズ[V]>サイズ[息子[X]])息子[X] = V。
        サイズ[X] + = サイズ[V]。
    }
} 
ボイド DFS2(int型のx、int型SP){ 
    トップ[X] = SP。
    TID [X] = ++ TOT。
    もし(息子[X]!)を返します
    DFS2(息子[X]、SP)。
    以下のためにint型 I = hの[X]; I; I = W [i]は.nxt){
         int型、V = W [i]は.TO。
        もし(V == PRT [X] || V ==息子[X])続けます
        DFS2(V、V); 
    } 
} 
インラインINT LCA(int型のx、int型のY){
     一方(上面[X] ^ トップ[Y]){
        もし(DEP [TOP [X] < DEP [トップ[Y])スワップ(X、Y)
        X = PRT [TOP [X]]。
    } 
    もし(DEP [X]> DEP [Y])スワップ(X、Y)
    リターンのx; 
} 
インラインINT lowbit(INT X){
     戻り X&( - X)。
} 
インラインボイド更新(int型のx、int型 D、INT C []){
     場合(!X)のリターン;
    一方、(x <= N)C [X] + = D、X + = lowbit(X)。
} 
インラインINTクエリ(INT X、 int型C []){
     int型の和= 0 一方、(X)の和+ = C [x]は、x軸= lowbit(X)。
    戻り値の合計。
} 
インラインボイド追加(int型のx、int型D){ 
    更新(TID [x]は、D、C1)。
    アップデート(TID [x]は、DEP [X] * D、C2)。
} 
インラインINTは(ASK int型のx、int型、YをINT C []){
     戻りクエリ(Y、C)-query(X- 1 、C)。
} 
{main()の符号付き
    のN = 読み取ります()。
    INTX、Y、D。
    以下のためにint型 i = 1 ; iがn <; iは++ ){ 
        X =リード()+ 1 
        Y =リード()+ 1 
        AddEdge(X、Y)
        AddEdge(Y、X)。
    } 
    DFS1(101 )。
    DFS2(11 )。
    M = 読み取ります();
    char型のCH;
    一方、(M-- ){
         DO CH = GETCHAR()。
        しばらく(CH!= ' A '!&& CH = ' Q ' );
        もし(CH == ' A ' ){ 
            X =リード()+ 1 
            Y =リード()+ 1 
            D = 読み取ります();
            INT U = LCA(X、Y)
            (X、D)を加えます。
            (Y、D)を加えます。
            (、Uを追加 - D)。
            追加(PRT [U]、 - D)。
        } { 
            X =リード()+ 1 INT TMP =尋ねる(TID [x]は、TID [X] +サイズ[X] - 1、C1)。
            プリント(ASK(TID [x]は、TID [X] +サイズ[X] - 1、C2)-tmp×(DEP [X] - 1)、' \ n ' ); 
        } 
    } 
    戻り 0 
}


なぜ2つのDFSが書かれていましたか?私は木のセクションLCAをお願いしたいと思いますので、

おすすめ

転載: www.cnblogs.com/soledadstar/p/11521865.html