CF GYM 103102J
題目
每個點都有 \(\frac{1}{2}\) 的概率有寶藏,現在給出每個點與離它最遠的寶藏的距離 \(d_i\),求在此條件下每個點有寶藏的概率,輸出寶藏編號 (以概率為第一關鍵字,編號為第二關鍵字升序排列)
題解
條件概率題。。設 \(P(A|B)\) 表示在 \(B\) 事件發生的情況下 \(A\) 事件發生的概率
現在知道了每個點與離它最遠寶藏的距離,那麼我們可以發現對於一個根 \(u\) 來說,所有 深度 \(>d_u\) 的一定都不可能有寶藏,且它限制了 深度 \(=d_u\) 的點集中一定至少有一個點有寶藏,假如不考慮其它點的限制,那麼對於 深度 \(<d_u\) 的點,概率都不會受到 \(u\)
但現在有了其它點的限制,該怎麼做?
有一個性質:樹上一個點 \(u\) 到一個點集 \(S\) 中的點最遠距離,一定是由 \(u\) 與 \(S\) 的直徑端點 \(v_1,v_2\) 其中一個構成的。由此我們可以發現每個點的 \(d_i\) 值實際上只表示了它距離 寶藏點集 直徑兩個端點的最大值,那麼直徑的中點一定是 \(d_i\) 值最小的。
先考慮直徑長度為偶數,即只有一箇中點,\(d\) 陣列中只有一個最小值。設這個點為 \(v\) ,將其當根,則它的限制為: 深度 \(=d_v\) 的點集中,至少有兩個 不同 子樹內的點有寶藏;\(< d_v\) 的點集,它們的 \(d\)
這麼一分類,可以發現 深度 \(<d_v\) 的點沒有受到任何限制,概率仍然是 \(\frac{1}{2}\),\(>d_v\) 的點概率也一定是 \(0\),現在只需要考慮 \(=d_v\) 的點之間概率的大小關係。
可以發現,對於每個點 \(u\) ,設事件 \(A\) 為 “ \(u\) 點有寶藏,且除了該點所屬子樹之外,還有至少一棵另外子樹 深度\(=d_v\) 的點處有寶藏”,事件 \(B\)
\(P(A)\) 可以拆成兩部分來看 “ \(u\) 點有寶藏” 的概率仍然是每個點都一樣,即 \(\frac{1}{2}\) 。那麼概率的區別就在於 “還有至少一棵另外子樹 深度\(=d_v\) 的點處有寶藏” 設 深度\(=d_v\) 的點的總個數為 \(sum\),點 \(u\) 所屬子樹中 有 \(siz_u\) 個點 深度\(=d_u\) ,概率即為 \(1-(1-\frac{1}{2})^{sum-siz_u}\) ,由此可得 \(siz_u\) 越大,出現寶藏的概率越小。
直徑長度為奇數,即有兩個中點,與上面類似考慮即可。
PS:這道題由 點到點集最遠距離 轉化到了直徑上的問題。。然後分析一下,奇奇怪怪的限制少了很多。。
const int N=3e5+5;
int n,x,y,a[N],id,minn=1e9,deep[N],flag,pre;
vi v[N],g[N],f[N],ans,cy;
vector<pii>w;
void dfs(int u,int fa,int id){
deep[u]=deep[fa]+1;
if(deep[u]<minn)ans.pb(u);
else if(deep[u]==minn)f[id].pb(u);
else cy.pb(u);
for(auto i:v[u]){
if(i==fa)continue;
dfs(i,u,id);
}
}
int main(){
#ifdef newbiewzs
#else
#endif
n=read();
for(int i=1;i<n;i++){
x=read();y=read();
v[x].pb(y);
v[y].pb(x);
}
for(int i=1;i<=n;i++)a[i]=read();
for(int i=1;i<=n;i++){
if(minn>a[i]){
minn=a[i];id=i;
}
}
for(int i=1;i<=n;i++){
if(minn==a[i] && id!=i)flag=1,pre=i;
}
if(flag){
dfs(pre,id,pre);
for(auto ta:f[pre]){
w.pb(mp(f[pre].size(),ta));
}
memset(deep,0,sizeof(deep));
dfs(id,pre,id);
for(auto ta:f[id]){
w.pb(mp(f[id].size(),ta));
}
}
else{
for(auto tmp:v[id]){
dfs(tmp,id,tmp);
for(auto ta:f[tmp]){
w.pb(mp(f[tmp].size(),ta));
}
}
if(minn==0)w.pb(mp(0,id));
else ans.pb(id);
}
sort(w.begin(),w.end());
sort(ans.begin(),ans.end());
sort(cy.begin(),cy.end());
for(auto ta:w){
cout<<ta.se<<" ";
}
for(auto tb:ans){
cout<<tb<<" ";
}
for(auto tc:cy){
cout<<tc<<" ";
}
return 0;
}