七彩樹 HYSBZ 4771線段樹合併

2021-09-09 09:02:40 字數 3418 閱讀 6634

本題是查詢乙個節點x的字樹內深度與其相差不超過d的節點有多少種顏色。如果單純考慮有多少個點,應該如何求?此時我們應該考慮如何維護深度在乙個區間內且是x的後代的資訊。我們可以每個節點用一顆以下標為權值的線段樹來維護(後面記為線段樹x)。用線段樹合併來完成所有資訊的處理。但如何查詢深度在乙個區間裡的資訊呢?我們可以將每個節點重新以深度編號,編號與深度正相關(也就是編號越大的點深度越大),在預處理處每個深度最大的編號。這樣就可以區間求和來解決這一簡化後的問題。

對於「出現了多少種本質不同的顏色」這一句話,不難聯想到turing tree這道題。只不過變為了在子樹內查詢而不是在序列上,但大體還是類似的。

相同顏色的節點,我們只用深度最淺(也就是離根最近)的節點。故我們可以對每個節點再開乙個線段樹維護這個節點的子樹內每種顏色的節點的最淺位置(後面記為線段樹y),每次線段樹合併時去掉深度大的顏色相同的點在當前節點的線段樹x裡的貢獻。每個節點的線段樹x只存每種顏色所在深度最淺的位置(重新編號後的)。

題目裡的小細節注意一下。(1<=t<=500),如果對每一組測試資料都清空陣列會tle,由於n和m的總和不超過500000,故每次只用清空上次使用過的陣列即可。

#include

#include

#include

#define m 100005

#define inf 1061109567

using

namespace std;

bool cur1;

void

check_max

(int

&x,int y)

void

check_min

(int

&x,int y)

struct eedge[m<<1]

;int tot,head[m]

;void

addedge

(int a,

int b)

int c[m]

,fa[m]

,dep[m]

,n,id;

int id[m]

;//按照深度排序

int id_dep[m]

;//每個排序後的節點的深度

struct segt2

segt2()

void

clear()

void

updata

(int l,

int r,

int x,

int op,

int&tid)

intquery

(int l,

int r,

int lx,

int rx,

int tid)

intmerge

(int x,

int y,

int l,

int r)

void

text

(int tid,

int l,

int r)

}st2;

struct segt1

segt1()

void

clear()

void

updata

(int l,

int r,

int x,

int d,

int&tid)

return;}

int mid=

(l+r)

>>1;

if(x<=mid)

updata

(l,mid,x,d,lson[tid]);

else

updata

(mid+

1,r,x,d,rson[tid]);

}int

query

(int l,

int r,

int x,

int&tid)

intmerge

(int x,

int y,

int l,

int r)

int res=

max(num[x]

,num[y]);

if(res<=n)st2.

updata(1

,n,res,-1

,st2.root[pc]);

//刪去深度較大的

num[tid]

=min

(num[x]

,num[y]);

return tid;

}int mid=

(l+r)

>>1;

lson[tid]

=merge

(lson[x]

,lson[y]

,l,mid)

; rson[tid]

=merge

(rson[x]

,rson[y]

,mid+

1,r)

;return tid;

}}st1;

int dep_mx[m]

;void

dfs(

int now)

}void

redfs

(int now)

st1.pc=now;

st1.

updata(1

,id,c[now]

,id[now]

,st1.root[now]);

}bool

cmp(

int x,

int y)

void

init()

int b[m]

,p[m]

;bool cur2;

intmain()

for(

int i=

1;i<=n;i++

)p[i]

=i;dfs(1

);sort

(p+1

,p+n+

1,cmp)

;//此處得到的p[i]為深度編號為i的點為p[i]

for(

int i=

1;i<=n;i++

)id[p[i]

]=i;

//重新標號,使id[i]為i這個點的深度編號

for(

int i=

1;i<=n;i++

)id_dep[id[i]

]=dep[i]

;//存每乙個編號對應的深度

for(

int i=

1;i<=n;i++

)check_max

(dep_mx[dep[i]

],id[i]);

//預處理每個深度最大的編號

redfs(1

);int ans=0;

while

(m--)}

return0;

}

主席樹 BZOJ 4771 七彩樹

感謝帶我飛的rxd大爺 我們先考慮不管深度限制可修改我們怎麼做 就是把每種顏色按照dfs序排列 然後給這些點都 1 但是相鄰兩個的lca處要 1 這樣子樹不同顏色數就是子樹和 然後我們把深度限制 看做按照深度的順序加點 加點我們需要維護什麼 每種顏色的序列 這個用set或平衡樹 在序列中插入 我們對...

BZOJ4771 七彩樹(主席樹)

點此看題面 考慮乙個子樹內所有點 dfs 序是連續的,所以我們可以將其轉化為序列然後用線段樹維護。又由於有深度限制,所以可以對不同深度建不同版本,使用主席樹。但是,本質不同顏色應該如何維護?考慮對於每一種顏色,如果有兩個該顏色的點同時出現,則相當於將這兩個點的權值分別加 1 而把它們 lca 的權值...

BZOJ4777 七彩樹 線段樹合併

題目鏈結 題意 給你乙個n nn個點的樹,每個點有乙個範圍是1 n 1 n1 n的權值,可能會有重複。每次問你乙個點的子樹內與它深度差不超過x xx題解 感覺一看就很線段樹合併,因為如果沒有不同權值的限制,只問乙個點子樹內與它深度差不超過x xx的點的個數,就是乙個經典的線段樹合併的題了。但是現在的...