JZOJ5058 採蘑菇(O n 演算法,慎入)

2021-10-08 21:42:42 字數 3180 閱讀 3257

題目描述:

a君住在魔法森林裡,魔法森林可以看做一棵n個結點的樹,結點從1~n編號。樹中的每個結點上都生長著蘑菇。蘑菇有許多不同的種類,但同乙個結點上的蘑菇都是同一種類,更具體地,i號結點上生長著種類為c[i]的蘑菇。

現在a君打算出去採蘑菇,但他並不知道**的蘑菇更好,因此他選定起點s後會等概率隨機選擇樹中的某個結點t作為終點,之後從s沿著(s,t)間的最短路徑走到t.並且a君會採摘途中所經過的所有結點上的蘑菇。

現在a君想知道,對於每乙個結點u,假如他從這個結點出發,他最後能採摘到的蘑菇種類數的期望是多少。為了方便,你告訴a君答案*n的值即可。

資料範圍:

30%的資料:n <= 2000

另有20%的資料:給出的第i條邊為

另有20%的資料:蘑菇的種類最多3種

100%的資料:1 <= n <= 3*10^5 , 0 <= c[i] <= n

這道題有虛數做法,有換根線段樹做法,也有點分治做法。

它們(除了虛樹,因為我並不會)都帶有乙隻log。雖然這道題時限比較寬鬆,但是有一位dalao想出了o(n)的做法。

我們隨便取乙個點為根。

定義一下:

s zx

sz_sz

x​為以x

xx為根的子樹的大小,upx

up_up

x​為從x

xx到根的路徑上,離x

xx最近的且顏色與x

xx相同的祖先的與x

xx在同一條路徑上的兒子。

假設我們做到節點u

uu,顏色為c

cc。考慮經過x

xx的路徑的貢獻。

黑色的節點表示與u同色的節點。

f

ff為離x

xx最近的且顏色與x

xx相同的祖先,x

xx為upu

up_up

u​。假設以x

xx為根的子樹內的節點為起點,其它節點為終點,那麼很顯然以x

xx為根的子樹內每個節點都能接受到其它節點個數的貢獻,也就是n−s

zxn-sz_

n−szx​

。同時另sum

xsum_

sumx

​表示upup

up值為x

xx的節點,以它們為根的子樹大小的總和,貢獻加上sum

xsum_

sumx​。

但是不難發現,這樣會算重。

以u

uu為例,它的子樹內,路徑上有顏色c

cc的貢獻應該至少來自u

uu。同理,它也沒有sum

xsum_

sumx

​的貢獻。相當於這一次它們什麼貢獻都沒有獲得。

總結的來說,x

xx的子樹內,我們先全部加上n−s

zx+s

umxn-sz_+sum_

n−szx​

+sum

x​。同時對於u

uu及和它等概念的節點(例如它旁邊那個小黑),它們並沒有貢獻。但是為了方便,不操作等價於再減去n−s

zupu

+sum

upun-sz_}+sum_}

n−szup

u​​+

sumu

pu​​

。那麼還有一種情況,節點u

uu沒有upup

我們直接統計這類節點的,以它們為根的子樹大小,總和記為vvv。

那麼不屬於這些節點的點可以獲得v

vv的貢獻,屬於這些節點的點沒有獲得貢獻。

最後,因為沒有記以自己為起點的貢獻,所以都加上nnn。

對於所有的操作,在dfs

dfsdf

s序上,一次操作對應的點都是連續的,所以可以用差分來實現。時間複雜度o(n

)o(n)

o(n)

。最後再次膜拜蔡bir

dbir

dbirdbird

birdbi

rd,想出這個神仙做法。

並十分感謝z_y_s為我這個蒟蒻講解這個神仙演算法。

#include

#include

#include

using

namespace std;

const

int n=

3e5+

1000

;int n;

int c[n+1]

;vector<

int> e[n+1]

,e1[n+1]

,s[n+1]

;int siz[n+1]

,id[n+1]

,up[n+1]

,sum[n+1]

;void

dfs(

int u,

int fa)

sum[up[u]]+

=siz[u];}

int tree[n+1]

;void

update

(int a,

int b,

int c)

void

solve

(int u,

int fa)

}int num[n+1]

,ans[n+1]

;bool

cmp(

int x,

int y)

intmain()

dfs(1,

0),solve(1

,0);

for(

int i=

0;i<=n;i++

)for

(int i=

1;i<=n;i++

) ans[i]

=ans[i-1]

+tree[i]

;for

(int i=

1;i<=n;i++

)printf

("%d\n"

,ans[id[i]

]+n)

;return0;

}

z_y_sdalao的**qwq。

題解 P5058 ZJOI2004 嗅探器

題目鏈結 題目大意 給定乙個無向圖,求乙個編號最小的點 p 使得刪掉 p 後 s 和 t 不連通 tarjan 演算法 分析 首先我們要明確 點 p 一定是割點,因為只有你刪掉乙個點後圖不連通才有可能使得 s 和 t 不連通,然後我們可以用 tarjan 來做這個事情 常規求割點是什麼,時間戳 df...

P5058 ZJOI2004 嗅探器 割點

一開始看到它的時候,想都沒想直接cv了割點的模板。結果是這樣的 再次讀題,發現是只用找u v路徑上的最小割點,改一下就a了 ac includeusing namespace std const int maxn 1e6 7 struct nodeedge 2 maxn inthead maxn c...

洛谷P5058 ZJOI2004 嗅探器

某軍搞資訊對抗實戰演習,紅軍成功地侵入了藍軍的內部網路,藍軍共有兩個資訊中心,紅軍計畫在某台中間伺服器上安裝乙個嗅探器,從而能夠偵聽到兩個資訊中心互相交換的所有資訊,但是藍軍的網路相當的龐大,資料報從乙個資訊中心傳到另乙個資訊中心可以不止有一條通路。現在需要你盡快地解決這個問題,應該把嗅探器安裝在哪...