L - 芜湖塔台请求起飞
生活随笔
收集整理的這篇文章主要介紹了
L - 芜湖塔台请求起飞
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
L - 蕪湖塔臺請求起飛
題目大意
給出一棵大小為 n n n的樹,有如下操作:
- 更改一個節點的權值
- 查詢從x到y路徑上的權值和
- 查詢從x到y路徑上的最大權值
題解
如果是在一個序列中,上面的操作非常容易用線段樹來完成,但是在樹上并不能。
于是就要想一個辦法使得樹變成一個序列。
很顯然,就是樹鏈剖分。
利用倍增求LCA,然后分別就是從x到LCA與從y到LCA的答案。
修改操作就直接在線段樹上完成。
時間復雜度
線段樹上一次查詢的復雜度是 O ( log ? n ) O(\log n) O(logn)的,
因為重邊是連在 d f n dfn dfn一起的,可以一起查詢,于是查詢的次數就取決于輕邊的次數。
根據重邊的性質,可以知道,向下每走過一條輕邊,子樹大小至少減半,
那么最多走過的輕邊數量就是 l o g n log_n logn?。
所以總的時間復雜度是 O ( q × log ? 2 n ) O(q\times \log^2 n) O(q×log2n)。
Tag
樹鏈剖分
線段樹
倍增LCA
code
//#pragma GCC optimize (2) //#pragma G++ optimize (2) #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #include <iostream> #define G getchar #define ls(x) (x << 1) #define rs(x) (x << 1 | 1) #define mx(x) a[x].mx #define s(x) a[x].s using namespace std;int read() {char ch;for(ch = G();(ch < '0' || ch > '9') && ch != '-';ch = G());int n = 0 , w;if (ch == '-'){w = -1;ch = G();} else w = 1;for(;'0' <= ch && ch <= '9';ch = G())n = (n<<1)+(n<<3)+ch-48;return n * w; }const int N = 30005; int dfn [N] , son[N] , tot , n , m , fa [16] [N] , x , y , dep [N]; int nxt [ N << 1] , lst [N] , to [N << 1] , si [N] , v [N] , top [N]; int opv , opl , opr , opt , pos;struct node {int mx , s; }a[N << 2];void dfs_1 (int x) {si [x] = 1;for (int i = lst [x] ; i ; i = nxt [i]){if (to [i] ^ fa [0] [x]){fa [0][ to[i] ] = x;dfs_1(to[i]);si[x] += si[to[i]];if (si[to[i]] > si[son[x]]) son[x] = to[i];}} }void dfs_2 (int x) {dep[x] = dep[fa[0][x]] + 1;dfn [x] = ++ tot;if (son[x]){top[son[x]] = top[x];dfs_2(son[x]);}for (int i = lst [x] ; i ; i = nxt [i])if (dfn[to[i]] == 0){top[to[i]] = to[i];dfs_2(to[i]);} }int lca (int x , int y) {if (dep[x] < dep[y]) swap(x , y);for (int i = 15 ; i >= 0 ; i--)if (dep[fa[i][x]] >= dep[y]) x = fa[i][x];for (int i = 15 ; i >= 0 ; i--)if (fa[i][x] ^ fa[i][y]){x = fa[i][x];y = fa[i][y];}if (x ^ y) return fa[0][x];else return x; }void ins (int x , int y) {nxt[++tot] = lst[x];to[tot] = y;lst[x] = tot; }void updata (int x) {mx(x) = max(mx(ls(x)) , mx(rs(x)));s(x) = s(ls(x)) + s(rs(x)); }void work (int x , int l , int r) {if (opl <= l && r <= opr){switch (opt){case 1:{mx(x) = s(x) = opv;break;}case 2:{opv = opv + s(x);break;}case 3:{opv = max(opv , mx(x));break;}}return;}int m = (l + r) >> 1;if (opl <= m) work(ls(x) , l , m);if (m < opr) work(rs(x) , m + 1 , r);updata(x); }void calc (int x , int y) {for (; dep[top[x]] > dep[y] ;){opl = dfn[top[x]];opr = dfn[x];work(1 , 1 , n);x = fa[0][top[x]];}opl = dfn[y];opr = dfn[x];work(1 , 1 , n); }int main() {freopen("l.in","r",stdin);//freopen("l.out","w",stdout);n = read();for (int i = 1; i < n; ++i){x = read();y = read();ins (x , y);ins (y , x);}dfs_1(1);for (int i =1 ; i < 16; i++)for (int j = 1 ; j <= n ; j++)fa[i][j] = fa[i - 1][fa[i - 1][j]];tot = 0;top[1] = 1;dfs_2(1);opt = 1;for (int i = 1 ; i <= n ; i++){opv = read();opl = opr = dfn[i];v[i] = opv;work(1 , 1 , n);}m = read();for (int i = 0; i < m; ++i){opt = read();x = read();y = read();pos = lca(x , y);if (opt == 1){opl = opr = dfn[x];opv = y;v[x] = y;work(1 , 1 , n);}else{if (opt == 2) opv = -v[pos]; else opv = v[pos];calc(x , pos);calc(y , pos);printf("%d\n", opv);}}return 0; }總結
以上是生活随笔為你收集整理的L - 芜湖塔台请求起飞的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 2020最难求职年,程序员职场面试 “防
- 下一篇: 为什么那些美事没有实现---生活中小事有