[ニウケプラクティス61F]アップルツリーポイントツリー、動的に開くラインツリー

リンゴの木

       すべての重心がツリーに接続されている場合、このツリーの高さがログに記録されます。前処理は、ツリー上の各ノードからすべての子ノードまでの距離(元のツリー上の距離)を再構築します。クエリと変更ごとに、再構築ツリーを連続してジャンプし、各ノードがクエリの動的開始ポイントを持つラインツリーを開きます。ツリーの高さはlognなので、時間の複雑さはnlognlognです。スペースの複雑さもnlognlognです。2つのポイント間の距離は、map、lca、または各ノードとi番目のレイヤーの親ノード間の距離を使用して保存できます。

 

#include <bits / stdc ++。h>
 using  namespace std;
const  int N = 1e5 + 10 ;
const  int M = 1e5 + 10 ;
const  int maxn = 1e7;
const  int INF = 0x3f3f3f3f ;
int head [N]、ver [ 2 * M]、edge [ 2 * M]、nex [ 2 * M]、tot = 1 ; 
inline void add(int x、int y、int z){ 
    ver [ ++ tot] = y、edge [tot] = z、nex [tot] = head [x]、head [x] =  tot;
}

 int lc [maxn]、rc [maxn]、Min [maxn]、cnt = 0、rt [N]; // rt:线段树根
void insert(int&o、int pos、int v、int l、int r){
     if(o == 0)Min [o = ++ cnt] = INF;
    if(l == r){Min [o] = min(Min [o]、v); return ;}
     int m =(l + r)>> 1 ;
    if(pos <= m)insert(lc [o]、pos、v、l、m);
    それ以外の場合、 insert(rc [o]、pos、v、m + 1 、r); 
    Min [o] = min(Min [lc [o]]、Min [rc [o]]);
} 
int  query(int o、int a、int b、int l、int r){
     if(o == 0return INF;
    if(a <= l && b> = r)return Min [o];
    int m =(l + r)>> 1、res = INF;
    if(a <= m)res = query(lc [o]、a、b、l、m);
    if(b> m)res = min(res、query(rc [o]、a、b、m + 1 、r));
    解像度を返す; 
} 

int vis [N]、sz [N]、sub_sz、max_sz、root;
void get_root(int x、int fa){
     int max_part = 0 ; sz [x] = 1 ;
    forint i = head [x]; i; i = nex [i]){
         int y = ver [i]; if(y == fa || vis [y])続行; 
        get_root(y、x); sz [x] + = sz [y]; 
        max_part = max(max_part、sz [y]); 
    } 
    max_part = max(max_part、sub_sz- sz [x]);
    if(max_part <max_sz){max_sz = max_part; root = x;} 
} 
int v [N]、fa [N]、dep [N]、dis [N] [ 20 ];
void get_dis(intx、 intfa、int d){ 
    dis [x] [dep [root]] = d; //ここにルート刚好是重心 
    挿入(rt [ルート]、v [x]、d、1 、N);
    forint i = head [x]; i; i = nex [i]){
         int y = ver [i]; if(y == fa || vis [y])続行; 
        get_dis(y、x、d + edge [i]); 
    } 
} 
void divide(int x、int depth){ 
    vis [x] = 1 ; 
    dep [x] = 深さ; 
    get_dis(X、00のInt tot_sz = sub_sz; // 現在処理ツリーサイズ
    のためINT Iは=頭[X]; I; I = NEX [I]){
         int型 Y =版[I]; IF(VIS [Y])continue ; 
        max_sz = INF; 
        sub_sz = sz [y]> sz [x]?tot_sz-sz [x]:sz [y]; // 
        サブツリーのサイズを取得 get_root(y、0 ); 
        fa [root] = x; 
        除算(ルート、深さ + 1 ); 
    } 
} 

int main(){
     int n、m、op、u、x、y、z; 
    Min [ 0 ] =INF; 
    scanf(" %d%d "、&​​n、&m);
    forint i = 1 ; i <= n; ++ i)scanf(" %d "、v + i);
    forint i = 1 ; i <n; ++ i){ 
        scanf(" %d%d%d "、&​​x、&y、&z); 
        add(x、y、z); add(y、x、z); 
    } 
    sub_sz = n; max_sz = INF; 
    get_root(10 ); 
    divide(root、0 );
    while(m-- ){
        scanf(" %d "、&op);
        if(op == 1 ){ 
            scanf(" %d%d "、&​​x、&y); z = x;
            while(z)insert(rt [z]、y、dis [x] [dep [z]]、1、N)、z = fa [z]; 
        } else { 
            scanf(" %d%d%d "、&​​u、&x、&y);
            int ans = INF; z = u;
            while(z)ans = min(ans、dis [u] [dep [z]] + query(rt [z]、x、y、1、N))、z = fa [z];
            if(ans == INF)puts(" -1 " );
            else printf(" %d \ n "2 * ans); 
        } 
    } 
    return  0 ; 
}
コードを表示

 

おすすめ

転載: www.cnblogs.com/judp/p/12704161.html