1. 程式人生 > >[BZOJ 3306] 樹

[BZOJ 3306] 樹

i++ urn pri father ret lse 解決 php %s

[題目鏈接]

https://www.lydsy.com/JudgeOnline/problem.php?id=3306

[算法]

若沒有換根操作 , 那麽“查詢子樹最小值”就可以用DFS序 + 線段樹解決

進一步地 , 可以發現換根後 , 造成影響的點在原根到新根的路徑上 , 根據這個性質 , 問題得到解決

時間復雜度 : O(NlogN)

[代碼]

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
#define MAXLOG 20
const
int inf = 2e9; typedef long long ll; typedef long double ld; struct edge { int to , nxt; } e[MAXN << 2]; int n , q , rt , timer , tot; int dfn[MAXN] , l[MAXN] , r[MAXN] , value[MAXN] , loc[MAXN] , head[MAXN] , depth[MAXN]; int up[MAXN][MAXLOG]; struct Segment_Tree { struct Node {
int l , r; int Min; } Tree[MAXN << 2]; inline void update(int index) { Tree[index].Min = min(Tree[index << 1].Min , Tree[index << 1 | 1].Min); } inline void build(int index , int l , int r) { Tree[index].l
= l; Tree[index].r = r; if (l == r) { Tree[index].Min = value[loc[l]]; return; } int mid = (l + r) >> 1; build(index << 1 , l , mid); build(index << 1 | 1 , mid + 1 , r); update(index); } inline void modify(int index , int pos , int v) { if (Tree[index].l == Tree[index].r) { Tree[index].Min = v; return; } int mid = (Tree[index].l + Tree[index].r) >> 1; if (mid >= pos) modify(index << 1 , pos , v); else modify(index << 1 | 1 , pos , v); update(index); } inline int query(int index , int l , int r) { if (l > r) return inf; if (Tree[index].l == l && Tree[index].r == r) return Tree[index].Min; int mid = (Tree[index].l + Tree[index].r) >> 1; if (mid >= r) return query(index << 1 , l , r); else if (mid + 1 <= l) return query(index << 1 | 1 , l , r); else return min(query(index << 1 , l , mid) , query(index << 1 | 1 , mid + 1 , r)); } inline int query() { return Tree[1].Min; } } SGT; template <typename T> inline void chkmax(T &x,T y) { x = max(x,y); } template <typename T> inline void chkmin(T &x,T y) { x = min(x,y); } template <typename T> inline void read(T &x) { T f = 1; x = 0; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -f; for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - 0; x *= f; } inline void addedge(int u , int v) { ++tot; e[tot] = (edge){v , head[u]}; head[u] = tot; } inline void dfs(int u , int father) { depth[u] = depth[father] + 1; dfn[u] = l[u] = ++timer; loc[timer] = u; up[u][0] = father; for (int i = 1; i < MAXLOG; i++) up[u][i] = up[up[u][i - 1]][i - 1]; for (int i = head[u]; i; i = e[i].nxt) { int v = e[i].to; if (v == father) continue; dfs(v , u); } r[u] = timer; } int main() { scanf("%d%d" , &n , &q); for (int i = 1; i <= n; i++) { int f; scanf("%d%d" , &f , &value[i]); if (f > 0) addedge(f , i); else rt = i; } dfs(rt , 0); SGT.build(1 , 1 , n); while (q--) { char type[5]; scanf("%s" , &type); if (type[0] == V) { int x , y; scanf("%d%d" , &x , &y); SGT.modify(1 , dfn[x] , y); } else if (type[0] == E) { int x; scanf("%d" , &x); rt = x; } else { int x; scanf("%d" , &x); if (x == rt) printf("%d\n" , SGT.query()); else if (l[x] <= l[rt] && r[x] >= r[rt]) { int y = rt; for (int i = MAXLOG - 1; i >= 0; i--) { if (depth[up[y][i]] > depth[x]) y = up[y][i]; } printf("%d\n" , min(SGT.query(1 , 1 , l[y] - 1) , SGT.query(1 , r[y] + 1 , n))); } else printf("%d\n" , SGT.query(1 , l[x] , r[x])); } } return 0; }

[BZOJ 3306] 樹