リンゴの木
すべての重心がツリーに接続されている場合、このツリーの高さがログに記録されます。前処理は、ツリー上の各ノードからすべての子ノードまでの距離(元のツリー上の距離)を再構築します。クエリと変更ごとに、再構築ツリーを連続してジャンプし、各ノードがクエリの動的開始ポイントを持つラインツリーを開きます。ツリーの高さは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 == 0)return 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 ; for(int 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); for(int 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、0、0) の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); for(int i = 1 ; i <= n; ++ i)scanf(" %d "、v + i); for(int 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(1、0 ); 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 ; }