您的位置:首页 > 其它

bzoj 3244: Noi2013树的计数

2016-07-29 16:07 344 查看
题目大意就是给出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 <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>

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<<k),j,x);
if(st_max[i][k] > x)
return find_b(i,i+(1<<k)-1,x);
return i;
}

int main()
{
cin >> 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<<k)+1][k]) < i || max2 > 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法