思路:首先求出樹上dfs序列,並且標記樹上每個節點開始遍歷以及最後回溯遍歷到的時間戳,由於需要修改樹上的某兩個節點之間的權值,如果parent[v] = u, 那麼說明修改之後的v的子樹到當前根的距離都會改變,由於遍歷到v時有開始時間戳以及結束時間戳,那麼處於這個區間所有節點都會影響到,於是我們可以通過陣列陣列來更新某個區間的值,只需令從區間起始點之後的每個值都增加乙個改變量了,令區間中止點之後的每個值都減小乙個改變量,這樣我們就可以得到處於該區間的值的改變量。至於如何求樹上兩個節點的lca,這裡可以使用rmq,o(n * log(n))的預處理,o(1)的查詢複雜度。\
#include #include #include #include #include using namespace std;
const int max_n = (200000 + 10000);
struct edge
edge (int _u, int _v, int _w, int _next) : u(_u), v(_v), w(_w), next(_next) {}
} ee[max_n << 2], edge[max_n << 2];
int ne, head[max_n];
void init()
void insert(int u, int v, int w)
int index, dfs_seq[max_n << 2]; //dfs序列
int first[max_n], end[max_n]; //first陣列表示第一次遍歷到的時間戳,end陣列表示最後回溯時遍歷到的時間戳
int parent[max_n], dep[max_n << 2]; //深度
int n, q, st, cost[max_n];
void dfs(int u, int fa, int d, int c)
end[u] = index;
}int dp[max_n][40]; //dp[i][j]表示從時間戳i開始,長度為(1 << j)的區間中深度最小的點的時間戳
void init_rmq()
}} int rmq_query(int l, int r)
int lca(int x, int y)
int c[max_n << 2];
int lowbit(int x)
void update(int i, int val)
}int getsum(int i)
return sum;
} int main()
index = 0;
dfs(st, st, 0, 0);
init_rmq();
memset(c, 0, sizeof(c));
for (int i = 1; i <= q; ++i) else }}
return 0;
}
LCA 樹狀陣列 樹上RMQ
思路 首先求出樹上dfs序列,並且標記樹上每個節點開始遍歷以及最後回溯遍歷到的時間戳,由於需要修改樹上的某兩個節點之間的權值,如果parent v u,那麼說明修改之後的v的子樹到當前根的距離都會改變,由於遍歷到v時有開始時間戳以及結束時間戳,那麼處於這個區間所有節點都會影響到,於是我們可以通過陣列...
RMQ問題的樹狀陣列解法
樹狀陣列中每個元素覆蓋了不同長度的子區間,類似於稀疏表 st 演算法的思想,每乙個陣列元素儲存了輸入數列a在該區間的最小值下標。注意 這裡樹狀陣列不是用來儲存區間累加值,而是區間的最小值下標。這裡針對預處理階段提供兩個演算法 方法1 參考以下實現 中的方法preprocess 採用類似於累加和中的u...
LCA與RMQ演算法
初始化 init rmq max i j 中存的是重j開始的2 i個資料中的最大值,最小值類似,num中存有陣列的值 for i 1 to n max 0 i num i for i 1 to log n log 2 for j 1 to n 1 2 i max i j max max i 1 j ...