[BZOJ 3306] 树
[题目链接]
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; }