1. 程式人生 > >hihocoder 樹的黑白染色

hihocoder 樹的黑白染色

都是 col 次數 決定 problems int 初始 http hihocoder

http://hihocoder.com/problemset/problem/1823

給你一棵樹,然後有兩種操作。

每個節點可以是黑色或者白色,初始時所有節點都是白色。

現在希望你依次進行M個操作,每種操作是以下兩種之一:

1. 將x節點塗黑

2. 輸出x節點到所有黑色節點的距離之和

hihocoder上出現次數很多的一個題。10^5的查詢次數來說的話,n*log(n)在python下也能通過。

本來想的方法是對於查詢與染色,某個為o(1)另一個是o(n),這樣妥妥不行。

對於n*log(n)來說,就是說其中的最大操作復雜度不能超過log(n),就是樹的高度唄。

思路如下:

每個點維持當前點到其所有子節點的染色點距離和d,以及該染色點數量n(包括該點本身)。這樣做一個後序遍歷是可以通過子節點的兩個數值得到根結點的兩個值的,這是前提知識。註意d和n的定義,僅關心該點為根的子樹的情況。

對於染色操作,因為每個節點的d和n僅僅由其子孫後代決定,所以只需向上更新到根結點即可。

對於查詢操作,你可以由父節點的d個n以及本身節點的d和n來推測出本身節點到兄弟姐妹節點的距離信息,假設本身是i,父節點是f,兩者距離是dis,那麽d[f]-d[i]-n[i]是父節點刨除節點i子樹後的d,然後這個距離加上(n[f]-n[i])*dis就是兄弟姐妹到該點距離了。

code:

n,m=[int(x)for x in raw_input().split()]
f=[-1]+[int(x)for x in raw_input().split()]
df=[-1]+[int(x)for x in
raw_input().split()] cl=[0]*n ns=[0]*n ds=[0]*n def add(i): if cl[i]!=0: return cl[i]=1 global ns,ds cnt=0 while i!=-1: ns[i]+=1 ds[i]+=cnt cnt+=df[i] i=f[i] def check(i): global ns,ds d=ds[i] ff=f[i] cnt=df[i] while ff!=-1: node_other
=ns[ff]-ns[i] dis_other=ds[ff]-ds[i]-ns[i]*df[i] dis=dis_other+node_other*cnt d+=dis i=ff ff=f[i] cnt+=df[i] print(d) return d for _ in range(m): t,p=[int(x) for x in raw_input().split()] if t==1: add(p) else: check(p)

hihocoder 樹的黑白染色