LOJ#2665 树的计数

题意:给你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\n", h[b[n]]);
107     return 0;
108 }
AC代码

 

posted @ 2019-04-26 16:55  huyufeifei  阅读(136)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜