[Noi2013]树的计数
来自FallDream的博客,未经允许,请勿转载,谢谢。
我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序。两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同,例如下面两棵树的DFS序都是1 2 4 5 3,BFS序都是1 2 3 4 5
现给定一个DFS序和BFS序,我们想要知道,符合条件的有根树中,树的高度的平均值。即,假如共有K棵不同的有根树具有这组DFS序和BFS序,且他们的高度分别是h1,h2,...,hk,那么请你输出
(h1+h2..+hk)/k
n<=200000
对bfs序分层 考虑同时符合dfs和bfs序的树满足什么条件
1.对于bfs连续的ab两点,假如a的bfs序小于b的bfs序,且a的dfs序大于b的,那么他们之间肯定是要分层的
2.另外 dfs序连续的ab两点,假如a的dfs序小于b的,且a的bfs序也小于b,那么显然它们的深度差不超过1,也就是说它们的bfs序区间之间最多分一层
3.第一个点要强制分层
所以考虑先把13条件都判一下,求出分层数的前缀和数组,然后把第2个条件判一下(如果它们之间已经分层了,那么就强制其他的不分层)
最后还没确定的点可分层可不分,贡献是0.5,答案是分层数加1再加上没确定的点的数量乘以0.5
复杂度O(n)
#include<iostream> #include<cstdio> #define getchar() (*S++) #define MN 200000 char BB[1<<26],*S=BB; using namespace std; inline int read() { int x = 0; char ch = getchar(); while(ch < '0' || ch > '9') ch = getchar(); while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x; } int D[MN+5],P[MN+5],B[MN+5],n,ans=0,x[MN+5],y[MN+5],q[MN+5],top=0; inline void mark(int a,int b){++y[a];--y[b];} int main() { fread(BB,1,1<<26,stdin); n=read();int j; for(register int i=1;i<=n;++i) P[j=read()]=i; for(register int i=1;i<=n;++i) D[B[i]=P[j=read()]]=i; for(register int i=1;i<n;++i) x[i]=x[i-1],(i==1||B[i]>B[i+1])?(ans+=2,++x[i],mark(i,i+1),0):0; for(register int i=1;i<n;++i) D[i]<D[i+1]?(x[D[i+1]-1]>x[D[i]-1]?(mark(D[i],D[i+1]),0):q[++top]=D[i]):0; for(register int i=1;i<=n;++i) y[i]+=y[i-1]; for(register int i=1;i<=top;++i) ans+=y[q[i]]==0; double Ans=(double)ans/2+1; printf("%0.3lf\n%0.3lf\n%0.3lf",Ans-0.001,Ans,Ans+0.001); return 0; }
FallDream代表秋之国向您问好!
欢迎您来我的博客www.cnblogs.com/FallDream