bzoj 3244: Noi2013树的计数

题目大意就是给出dfs序和bfs序,求树的期望高度


首先感谢Mektpoy的blog:树的计数——Mektpoy


Mektpoy的做法是O(nlogn)的,已经讲得比较清楚了,但还是看了好久才想清楚,所以多说两句。


1.当pos[B] = pos[A] + 1时,若B是A的儿子,因为bfs序相邻,那么B必须是A的下一层的第一个儿子,所以在这层之前不可能出现过bfs大于B的,即在此之前的dfs序中不能出现比B大的数,还是一个RMQ问题。


2.因为懒得写线段树了,就用st表来求RMQ。Mektpoy说的:"对于dfs序在B后面的点 对于任意一个这些点中bfs序>B的点 他前面(也就是B和这个点之间)若有一个 < A的点也不可以",只需求出最后一个比B大的数就能满足任意了,这里利用st表来递归O(logN)的求出最后一个比B大的数,再求之间最小的数,与A比较即可。


好像还有O(N)的算法,应该是利用更巧妙的性质,懒得看了(好渣)


/**************************************************************
    Problem: 3244
    User: cabinfever
    Language: C++
    Result: Accepted
    Time:1016 ms
    Memory:35676 kb
****************************************************************/
 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
 
using namespace std;
 
int dfs[200010];
int bfs[200010];
int haha[200010];
int pos[200010];
int n;
int st_max[200010][20];
int st_min[200010][20];
 
double ans = 0;
 
int find_b(int i,int j,int x)
{
    if(j == i)
        return j;
    int k = log2(j - i);
    if(st_max[j + 1 - (1 << k)][k] > x)
        return find_b(j+1-(1< x)
        return find_b(i,i+(1<> n;
    for(int i = 1; i <= n; i++)
        scanf("%d",&dfs[i]);
    for(int i = 1; i <= n; i++)
        scanf("%d",&bfs[i]);
    for(int i = 1; i <= n; i++)
    {
        haha[bfs[i]] = i;
        bfs[i] = i;
    }
    for(int i = 1; i <= n; i++)
    {
        dfs[i] = haha[dfs[i]];
        pos[dfs[i]] = i;
    }
    ans = 2;
    for(int i = 1; i <= n; i++)
    {
        st_min[i][0] = dfs[i];
        st_max[i][0] = dfs[i];
    }
    int k = log2(n) + 1;
    for(int j = 1; j < k; j++)
        for(int i = 1; i <= n; i++)
            if(i + (1 << j) <= n + 1)
            {
                st_min[i][j] = min(st_min[i][j-1],st_min[i + (1 << (j-1))][j-1]);
                st_max[i][j] = max(st_max[i][j-1],st_max[i + (1 << (j-1))][j-1]);
            }
    for(int i = 2; i < n; i++)
    {
        if(pos[i] > pos[i+1])
            ans++;
        else if(pos[i+1] > pos[i]+1)
            ans += 0;
        else
        {
            int j = find_b(pos[i+1],n,i+1);
            int k = log2(j - pos[i+1] + 1);
            int k2 = log2(pos[i]-1);
            int max2 = max(st_max[1][k2],st_max[pos[i] + 1 - (1 << k2)][k2]);
            if(min(st_min[pos[i+1]][k],st_min[j-(1< i + 1)
                ans += 0;
            else
                ans += 0.5;
        }
    }
    printf("%.3lf\n",(double)ans-0.001);
    printf("%.3lf\n",(double)ans);
    printf("%.3lf\n",(double)ans+0.001);    
    return 0;
}


你可能感兴趣的:(bzoj)