Spoj--375(树链剖分,线段树)
2014-10-05 13:10:03
思路:树链剖分启蒙题。树链剖分就是把一棵树剖分成轻链和重链。一个节点的重儿子的含义:所有儿子中以其为根的子树最大的子节点。
主要维护的几个值:
son[p]:p的重儿子
top[p]:p所在链的顶节点
fa[p]:p的父亲节点
sz[p]:以p为根的子树的结点数
dep[p]:p的深度(root为0)
w[p]:p节点在线段树中的位置
aw[p]:w[]数组的反含义,即线段树中节点在输入顺序中的编号
1 /************************************************************************* 2 > File Name: sp375.cpp 3 > Author: Nature 4 > Mail: 564374850@qq.com 5 > Created Time: Sat 04 Oct 2014 08:42:34 PM CST 6 ************************************************************************/ 7 8 #include <cstdio> 9 #include <cstring> 10 #include <cstdlib> 11 #include <cmath> 12 #include <vector> 13 #include <map> 14 #include <set> 15 #include <queue> 16 #include <iostream> 17 #include <algorithm> 18 using namespace std; 19 #define lp (p << 1) 20 #define rp (p << 1|1) 21 #define getmid(l,r) (l + (r - l) / 2) 22 #define MP(a,b) make_pair(a,b) 23 typedef long long ll; 24 const int INF = 1 << 30; 25 const int maxn = 10010; 26 27 int T,N; 28 int dep[maxn],sz[maxn],son[maxn],fa[maxn],top[maxn],tsz,w[maxn],tmax[maxn << 2]; 29 int first[maxn],next[maxn << 1],ver[maxn << 1],ecnt; 30 int e[maxn][3]; 31 32 inline int read(){ 33 int x = 0,f = 1;char ch = getchar(); 34 while(ch < '0' || ch > '9'){if(ch == '-')f=-1;ch = getchar();} 35 while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} 36 return x * f; 37 } 38 39 void Add_edge(int u,int v){ 40 next[++ecnt] = first[u]; 41 ver[ecnt] = v; 42 first[u] = ecnt; 43 } 44 45 void Dfs(int p){ 46 sz[p] = 1; 47 son[p] = -1; 48 int maxx = 0; 49 for(int i = first[p]; i != -1; i = next[i]) if(ver[i] != fa[p]){ 50 dep[ver[i]] = dep[p] + 1; 51 fa[ver[i]] = p; 52 Dfs(ver[i]); 53 if(sz[ver[i]] > maxx){ 54 son[p] = ver[i]; 55 maxx = sz[ver[i]]; 56 } 57 sz[p] += sz[ver[i]]; 58 } 59 } 60 61 void Build_tree(int p,int tp){ 62 w[p] = ++tsz; 63 top[p] = tp; 64 if(son[p] != -1) Build_tree(son[p],tp); 65 for(int i = first[p]; i != -1; i = next[i]) 66 if(ver[i] != son[p] && ver[i] != fa[p]) 67 Build_tree(ver[i],ver[i]); 68 } 69 70 void Update_tree(int a,int v,int p,int l,int r){ 71 if(l == r){ 72 tmax[p] = v; 73 return; 74 } 75 int mid = getmid(l,r); 76 if(a <= mid) Update_tree(a,v,lp,l,mid); 77 else Update_tree(a,v,rp,mid + 1,r); 78 tmax[p] = max(tmax[lp],tmax[rp]); 79 } 80 81 int Query_tree(int a,int b,int p,int l,int r){ 82 if(a <= l && r <= b) 83 return tmax[p]; 84 int res = -INF,mid = getmid(l,r); 85 if(a <= mid) res = max(res,Query_tree(a,b,lp,l,mid)); 86 if(b > mid) res = max(res,Query_tree(a,b,rp,mid + 1,r)); 87 return res; 88 } 89 90 int Find(int a,int b){ 91 int f1 = top[a],f2 = top[b]; 92 int ans = 0; 93 while(f1 != f2){ 94 if(dep[f1] > dep[f2]){ 95 swap(a,b); 96 swap(f1,f2); 97 } 98 ans = max(ans,Query_tree(w[f2],w[b],1,1,tsz)); 99 b = fa[f2]; 100 f2 = top[b]; 101 } 102 if(a == b) return ans; 103 if(dep[a] > dep[b]) swap(a,b); 104 return max(ans,Query_tree(w[son[a]],w[b],1,1,tsz)); 105 } 106 107 void Init(){ 108 tsz = -1; 109 fa[1] = dep[1] = 0; 110 memset(sz,0,sizeof(sz)); 111 memset(tmax,0,sizeof(tmax)); 112 memset(first,-1,sizeof(first)); 113 ecnt = 0; 114 } 115 116 int main(){ 117 char s[10]; 118 int a,b,c; 119 T = read(); 120 while(T--){ 121 N = read(); 122 Init(); 123 for(int i = 1; i < N; ++i){ 124 a = read(),b = read(),c = read(); 125 e[i][0] = a,e[i][1] = b,e[i][2] = c; 126 Add_edge(a,b); 127 Add_edge(b,a); 128 } 129 Dfs(1); 130 Build_tree(1,1); 131 for(int i = 1; i < N; ++i){ 132 if(dep[e[i][0]] > dep[e[i][1]]) swap(e[i][0],e[i][1]); 133 Update_tree(w[e[i][1]],e[i][2],1,1,tsz); 134 } 135 while(scanf("%s",s) != EOF){ 136 if(s[0] == 'D') break; 137 a = read(),b = read(); 138 if(s[0] == 'C') 139 Update_tree(w[e[a][1]],b,1,1,tsz); 140 else 141 printf("%d\n",Find(a,b)); 142 } 143 } 144 return 0; 145 }

浙公网安备 33010602011771号