题意:给你DFS序和BFS序,求树的期望高度。
解:先分析性质。
考虑到BFS序是分层的,DFS序的子树是一段,那么我们遍历BFS序并在DFS序上标记对应点的话,就会发现BFS序每一层都会把若干棵子树每个都分成若干个小子树,且换层的时候一定会是DFS序上第一个非空位置。
设每个点的期望深度为hi,那么就是要求BFS序最后一个点的h。考虑每个点的深度怎么算。如果当前点不是新一层的开头,那么它的h一定等于他在BFS序前面一个点的深度。如果是开头,那么就要等于它父亲的深度 + 1,我们可以在DFS序上把每个点的子树染色以查明该点的父亲。如果这两种情况都有可能,那么h就是这两种情况的平均数。
考虑什么时候只可能是一种情况。
当这个点在DFS序上的位置前于BFS序上前一个点在DFS序上的位置的时候,当前点一定是新一层的开头。
当这个点在DFS序上的位置后与BFS序上前一个点在DFS序上的位置的时候:如果这个点和BFS上前一个点在DFS序上的位置不相邻,那么这两个点一定在同一层。
相邻的时候,如果当前点在DFS序的前面还有空位,那么一定在同一层。否则考虑这个子树后面还有没有空位,如果有也一定在同一层,因为要换层的话一定要把后面的每个都走一遍。
实现的时候就用线段树维护颜色和区间和。
1 #include <bits/stdc++.h> 2 3 const int N = 200010; 4 5 int col[N << 2], sum[N << 2]; 6 int d[N], b[N], pos[N]; 7 double h[N]; 8 9 inline void pushdown(int o) { 10 if(!col[o]) return; 11 col[o << 1] = col[o << 1 | 1] = col[o]; 12 col[o] = 0; 13 return; 14 } 15 16 void add(int p, int l, int r, int o) { 17 if(l == r) { 18 sum[o] = 1; 19 return; 20 } 21 int mid = (l + r) >> 1; 22 if(p <= mid) add(p, l, mid, o << 1); 23 else add(p, mid + 1, r, o << 1 | 1); 24 sum[o] = sum[o << 1] + sum[o << 1 | 1]; 25 return; 26 } 27 28 int getSum(int L, int R, int l, int r, int o) { 29 if(L <= l && r <= R) return sum[o]; 30 int mid = (l + r) >> 1, ans = 0; 31 if(L <= mid) ans += getSum(L, R, l, mid, o << 1); 32 if(mid < R) ans += getSum(L, R, mid + 1, r, o << 1 | 1); 33 return ans; 34 } 35 36 void change(int L, int R, int v, int l, int r, int o) { 37 if(L <= l && r <= R) { 38 col[o] = v; 39 return; 40 } 41 pushdown(o); 42 int mid = (l + r) >> 1; 43 if(L <= mid) change(L, R, v, l, mid, o << 1); 44 if(mid < R) change(L, R, v, mid + 1, r, o << 1 | 1); 45 return; 46 } 47 48 int ask(int p, int l, int r, int o) { 49 if(l == r) return col[o]; 50 int mid = (l + r) >> 1; 51 pushdown(o); 52 if(p <= mid) return ask(p, l, mid, o << 1); 53 else return ask(p, mid + 1, r, o << 1 | 1); 54 } 55 56 int getKth(int k, int l, int r, int o) { 57 if(l == r) { 58 return r + (k > sum[o]); 59 } 60 int mid = (l + r) >> 1; 61 if(k <= sum[o << 1]) { 62 return getKth(k, l, mid, o << 1); 63 } 64 else { 65 return getKth(k - sum[o << 1], mid + 1, r, o << 1 | 1); 66 } 67 } 68 69 int main() { 70 71 int n; 72 scanf("%d", &n); 73 for(int i = 1; i <= n; i++) { 74 scanf("%d", &d[i]); 75 pos[d[i]] = i; 76 } 77 for(int i = 1; i <= n; i++) { 78 scanf("%d", &b[i]); 79 } 80 /// h[1] = 1 81 for(int i = 1; i <= n; i++) { 82 /// b[i] in pos[b[i]] 83 int p = pos[b[i]], lastp = pos[b[i - 1]]; 84 add(p, 1, n, 1); 85 int s = getSum(1, p, 1, n, 1); 86 int ed = getKth(s + 1, 1, n, 1) - 1; 87 /// [p, ed] 88 if(i == 1) { 89 h[b[i]] = 1; 90 } 91 else if(p == lastp + 1 && s == p && (ed < n ? getSum(ed + 1, n, 1, n, 1) : 0) == n - ed) { 92 int fr = ask(p, 1, n, 1); 93 if(fr != d[1]) h[b[i]] = (h[fr] + 1 + h[b[i - 1]]) / 2; 94 else h[b[i]] = h[fr] + 1; 95 } 96 else if(p < lastp) { /// new line 97 int fr = ask(p, 1, n, 1); 98 h[b[i]] = h[fr] + 1; 99 } 100 else { 101 h[b[i]] = h[b[i - 1]]; 102 } 103 change(p, ed, b[i], 1, n, 1); 104 } 105 106 printf("%.3f ", h[b[n]]); 107 return 0; 108 }