LOJ#2665 樹的計數

題意:給你DFS序和BFS序,求樹的指望高度。c++

解:先分析性質。ide

考慮到BFS序是分層的,DFS序的子樹是一段,那麼咱們遍歷BFS序並在DFS序上標記對應點的話,就會發現BFS序每一層都會把若干棵子樹每一個都分紅若干個小子樹,且換層的時候必定會是DFS序上第一個非空位置。spa

設每一個點的指望深度爲hi,那麼就是要求BFS序最後一個點的h。考慮每一個點的深度怎麼算。若是當前點不是新一層的開頭,那麼它的h必定等於他在BFS序前面一個點的深度。若是是開頭,那麼就要等於它父親的深度 + 1,咱們能夠在DFS序上把每一個點的子樹染色以查明該點的父親。若是這兩種狀況都有可能,那麼h就是這兩種狀況的平均數。code

考慮何時只多是一種狀況。blog

當這個點在DFS序上的位置前於BFS序上前一個點在DFS序上的位置的時候,當前點必定是新一層的開頭。get

當這個點在DFS序上的位置後與BFS序上前一個點在DFS序上的位置的時候:若是這個點和BFS上前一個點在DFS序上的位置不相鄰,那麼這兩個點必定在同一層。it

相鄰的時候,若是當前點在DFS序的前面還有空位,那麼必定在同一層。不然考慮這個子樹後面還有沒有空位,若是有也必定在同一層,由於要換層的話必定要把後面的每一個都走一遍。event

實現的時候就用線段樹維護顏色和區間和。ast

  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\n", h[b[n]]);
107     return 0;
108 }
AC代碼
相關文章
相關標籤/搜索