1. 程式人生 > >【BZOJ3244】【UOJ#122】【NOI2013]樹的計數

【BZOJ3244】【UOJ#122】【NOI2013]樹的計數

不同 判斷 != height 情況 alt jpg color 不同的

NOI都是醬的題怎麽玩啊,哇.jpg

原題:

我們知道一棵有根樹可以進行深度優先遍歷(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

2≤n≤200000

恩開始想了一下一點思路都沒有。。。。。。。。。好吧我應該想一想暴力的

直接看題解了,這裏只解釋題解

首先先把bfs調成1,2,3……n的形式,dfs跟著調方便討論

然後對於b=a+1

因為bfs是按層推,所以b要麽跟a一層,要麽比a多一層,即height[b]=height[a]+1或height[b]=height[a],如果在同一層則b一定在a的後面

如果dfs[a]>dfs[b],表示dfs的時候是先到a再到b,那麽a和b就不能在同一層,則height[b]=height[a]+1

如果dfs[a]<dfs[b],有兩種情況,dfs[b]!=dfs[a]+1,這個時候顯然只能是ab在同一層且a在b前面,註意因為bfs[b]=bfs[a]+1(註意bfs[a]=a)

如果dfs[b]=dfs[a]+1,還是有兩種情況,菊花或鏈,如果菊花就height[b]=height[a],如果鏈就height[b]=height[a]+1

盡管這種情況有機會是的height[b]大於height[a],但是這個未必會對答案造成影響

啥時候會造成影響呢,首先height[b]=height[a]+1,然後b是這一層最後一個點,這個時候對答案就貢獻了

怎麽判斷這種情況?當剩下的點都是b的子樹的時候就是這種情況,如果用flag[i]表示i有沒有被遍歷到,計一個r表示從最右邊起最多連續多少個flag[i]==1,l表示從左起最多連續多少個flag[i]==1,那麽當i-1=n-r+1-l,即左邊一截全是1,右邊一截全是1,中間全是0的時候就表示剩下的點全是b的子樹

因為還有height[b]=height[a]的情況而且這種情況對於後面沒有影響,因此此時給答案貢獻的期望值為0.5

為啥height[b]=height[a]+1會對答案有貢獻呢,因為b=a+1,前面是沿著bfs序一層一層推的,結合上面的性質就容易立即如果對答案貢獻

這種題完全沒思路啊,NOI怎麽玩啊QAQ

代碼:

技術分享
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cstring>
 5 #include<cmath>
 6 using namespace std;
 7 int rd(){int z=0,mk=1;  char ch=getchar();
 8     while(ch<0||ch>9){if(ch==-)mk=-1;  ch=getchar();}
 9     while(ch>=0&&ch<=9){z=(z<<3)+(z<<1)+ch-0;  ch=getchar();}
10     return z*mk;
11 }
12 int n,a[210000],b[210000];
13 int rvs[210000];
14 bool flg[210000];
15 int main(){freopen("ddd.in","r",stdin);
16     cin>>n;
17     for(int i=1;i<=n;++i)  a[i]=rd(),rvs[a[i]]=i;
18     for(int i=1;i<=n;++i)  b[i]=rvs[rd()];
19     int l=2,r=n+1;  double ans=2;
20     flg[1]=flg[2]=true;
21     for(int i=3;i<=n;++i){
22         if(b[i-1]>b[i])  ++ans;
23         else if(b[i]==b[i-1]+1)  ans+=(n-r+1+l==i-1)*0.5;
24         flg[b[i]]=true;
25         while((l<r) & flg[r-1])  --r;
26         while((l<r) & flg[l+1])  ++l;
27     }
28     printf("%.3lf\n%.3lf\n%.3lf\n",ans-0.001,ans,ans+0.001);
29     return 0;
30 }
View Code

【BZOJ3244】【UOJ#122】【NOI2013]樹的計數