SP375 QTREE - Query on a tree (樹剖)
阿新 • • 發佈:2019-05-04
cpp 圖片 操作 bubuko query push img eof 深度
不用特意判斷;兩個位置的深淺,樹剖中會判斷,詳見這裏
題目
SP375 QTREE - Query on a tree
解析
也就是個藍題,因為比較長
樹剖裸題(基本上),單點修改,鏈上查詢。
順便來說一下鏈上操作時如何將邊上的操作轉化為點上的操作:
可以看到這個題然我們對邊進行操作,我們的樹剖是對節點進行操作的,所以我們考慮把邊權變為點權。
發現我們節點的點權是連向它的邊的邊權,所以我們要操作邊權的話,我們操作的實際上是其連向點的點權,
假設我們要修改1-4之間的這兩條邊
我們修改的實際上就是這2,4兩個點
我們節點的點權為其父節點連向它的邊的邊權,所以我們鏈上修操作的時候,不要操作深度較低的節點,因為它代表的邊是它的父節點連向它的那一條,不是要操作的兩點之間的邊,就像上圖我們不操作1號節點一樣。
再說一下這個題的修改,因為我們是要修改邊權,我們的邊權給了點,所以我們找一下這條邊連的兩個點,判斷兩個點的深度,較深的那個是我們要修改的點。
然後這是SPOJ上的題,我不知道為啥我寫c++會掛,經king丨帝禦威大佬的指點才用c過的,%%%
代碼
#include <ctype.h> #include <stdio.h> #include <limits.h> #include <stdlib.h> #include <string.h> #define lson rt << 1 #define rson rt << 1 | 1 #define N 10007 int t, n, m, num, cnt; int head[N], a[N], w[N], son[N], size[N], f[N], top[N], dep[N], id[N], mx[N << 2]; class node { public : int nx, v, w; } e[N << 2]; void add(int u, int v, int w) { e[++num].nx = head[u], e[num].v = v, e[num].w = w, head[u] = num; } int max(int a, int b) { return a > b ? a : b; } #define swap(A, B) { int __T = A; A = B; B = __T; } void dfs1(int u, int fa) { size[u] = 1; for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != fa) { dep[v] = dep[u] + 1; f[v] = u; w[v] = e[i].w; //邊權賦給點 dfs1(v, u); size[u] += size[v]; if (size[v] > size[son[u]]) son[u] = v; } } } void dfs2(int u, int t) { id[u] = ++cnt; a[cnt] = w[u]; top[u] = t; if (son[u]) dfs2(son[u], t); for (int i = head[u]; ~i; i = e[i].nx) { int v = e[i].v; if (v != f[u] && v != son[u]) dfs2(v, v); } } void pushup(int rt) { mx[rt] = max(mx[lson], mx[rson]); } void build(int l, int r, int rt) { if (l == r) { mx[rt] = a[l]; return ; } int m = (l + r) >> 1; build(l, m, lson); build(m + 1, r, rson); pushup(rt); } void update(int L, int c, int l, int r, int rt) { if (l == r) { mx[rt] = c; return ; } int m = (l + r) >> 1; if (L <= m) update(L, c, l, m, lson); else update(L, c, m + 1, r, rson); pushup(rt); } int query(int L, int R, int l, int r, int rt) { if (L <= l && r <= R) return mx[rt]; int m = (l + r) >> 1, ans = -0x3f3f3f3f; if (L <= m) ans = max(ans, query(L, R, l, m, lson)); if (R > m) ans = max(ans, query(L, R, m + 1, r, rson)); return ans; } int query_chain(int x, int y) { int fx = top[x], fy = top[y], ans = -0x3f3f3f3f; while (fx != fy) { if (dep[fx] < dep[fy]) { swap(x, y); swap(fx, fy); } ans = max(ans, query(id[fx], id[x], 1, cnt, 1)); x = f[fx], fx = top[x]; } if (id[x] > id[y]) swap(x, y); ans = max(ans, query(id[x] + 1, id[y], 1, cnt, 1)); /*在這裏註意是id[x]+1->id[y],不要算上深度較淺的點*/ return ans; } int main() { scanf("%d", &t); while (t -- ) { num = cnt = 0; memset(head, -1, sizeof(head)); memset(dep, 0, sizeof(dep)); memset(id, 0, sizeof(id)); memset(a, 0, sizeof(a)); memset(w, 0, sizeof(w)); memset(top, 0, sizeof(top)); memset(size, 0, sizeof(size)); memset(e, 0, sizeof(e)); memset(mx, 0, sizeof(mx)); memset(son, 0, sizeof(son)); memset(f, 0, sizeof(f)); scanf("%d", &n); for (int i = 1, x, y, z; i < n; ++i) { scanf("%d%d%d", &x, &y, &z); add(x, y, z), add(y, x, z); } dfs1(1, 0), dfs2(1, 1); build(1, n, 1); char s[20]; int x, y; while (1) { scanf("%s", s); if (s[0] == 'D') break; else if (s[0] == 'C') { scanf("%d%d", &x, &y); x = dep[e[x << 1].v] > dep[e[(x << 1) - 1].v] ? e[x << 1].v : e[(x << 1) - 1].v; /*因為是無向邊,加了兩次,兩次的v都不是一個點*/ update(id[x], y, 1, n, 1); } else { scanf("%d%d", &x, &y); printf("%d\n", query_chain(x, y)); } } } return 0; }
SP375 QTREE - Query on a tree (樹剖)