Query on a tree 【SPOJ - QTREE】【樹鏈剖分+線段樹區間最大值】
阿新 • • 發佈:2018-12-25
題目連結
一道樹鏈剖分的基礎題,我的做法可能與廣大網友不大一樣,我將邊也算做是一個點,然後相當於是把兩個端點相互連線在邊所代表的那個點上,這樣更新邊就變成了更新點,查詢就是區間查詢。
一開始讀了道假題做了半天(最近總是在讀假題……),還以為是區間和,然後看到區間邊長最大值的時候,我整個人都奔潰了!!!
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef unsigned long long ull; typedef long long ll; const int maxN = 20005; const ll INF = 1e9 + 7; int N, cnt, head[maxN], root[maxN], depth[maxN], size[maxN], W_son[maxN], tot, topy[maxN], id[maxN], num; ll a[maxN], tree[maxN<<2], new_a[maxN]; struct Eddge { int nex, to; Eddge(int a=-1, int b=0):nex(a), to(b) {} }edge[maxN<<1]; void addEddge(int u, int v) { edge[cnt] = Eddge(head[u], v); head[u] = cnt++; } void dfs1(int u, int fa, int deep) { root[u] = fa; depth[u] = deep; size[u] = 1; for(int i=head[u]; i!=-1; i=edge[i].nex) { int v = edge[i].to; if(v == fa) continue; dfs1(v, u, deep+1); size[u] += size[v]; if(size[W_son[u]] < size[v]) { W_son[u] = v; } } } void dfs2(int u, int top) { topy[u] = top; id[u] = ++num; new_a[num] = a[u]; if(!W_son[u]) return; dfs2(W_son[u], top); for(int i=head[u]; i!=-1; i=edge[i].nex) { int v = edge[i].to; if(v == root[u] || v == W_son[u]) continue; dfs2(v, v); } } void buildTree(int rt, int l, int r) { if(l == r) { tree[rt] = new_a[l]; return; } int mid = (l + r)>>1; buildTree(rt<<1, l, mid); buildTree(rt<<1|1, mid+1, r); tree[rt] = max(tree[rt<<1], tree[rt<<1|1]); } void update(int rt, int l, int r, int qx, ll val) { if(l == r) { tree[rt] = val; return; } int mid = (l + r)>>1; if(qx<=mid) update(rt<<1, l, mid, qx, val); else update(rt<<1|1, mid+1, r, qx, val); tree[rt] = max(tree[rt<<1], tree[rt<<1|1]); } ll query(int rt, int l, int r, int ql, int qr) { if(ql<=l && qr>=r) return tree[rt]; int mid = (l + r)>>1; if(ql>mid) return query(rt<<1|1, mid+1, r, ql, qr); else if(qr<=mid) return query(rt<<1, l, mid, ql, qr); else return max( query(rt<<1, l, mid, ql, qr), query(rt<<1|1, mid+1, r, ql, qr) ); } void update_Point(int x, ll val) { update(1, 1, tot, id[x], val); } ll query_Range(int x, int y) { ll ans = -INF; while(topy[x] != topy[y]) { if(depth[topy[x]] < depth[topy[y]]) swap(x, y); ans = max(ans, query(1, 1, tot, id[topy[x]], id[x])); x = root[topy[x]]; } if(depth[x] > depth[y]) swap(x, y); ans = max(ans, query(1, 1, tot, id[x], id[y])); return ans; } void init() { memset(W_son, 0, sizeof(W_son)); memset(head, -1, sizeof(head)); cnt = num = 0; tot = 2*N-1; for(int i=0; i<maxN; i++) a[i] = -INF; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d", &N); init(); for(int i=1; i<N; i++) { int e1, e2; ll e3; scanf("%d%d%lld", &e1, &e2, &e3); a[N+i] = e3; addEddge(e1, N+i); addEddge(N+i, e1); addEddge(N+i, e2); addEddge(e2, N+i); } dfs1(1, 1, 0); dfs2(1, 1); buildTree(1, 1, tot); char s[20]; while(scanf("%s", s) && s[0]!='D') { if(s[0] == 'C') { int e1; ll e2; scanf("%d%lld", &e1, &e2); update_Point(N+e1, e2); } else { int e1, e2; scanf("%d%d", &e1, &e2); printf("%lld\n", query_Range(e1, e2)); } } } return 0; }