BZOJ4771 七彩樹(主席樹)

2022-05-14 14:12:22 字數 1621 閱讀 8070

點此看題面

考慮乙個子樹內所有點\(dfs\)序是連續的,所以我們可以將其轉化為序列然後用線段樹維護。

又由於有深度限制,所以可以對不同深度建不同版本,使用主席樹

但是,本質不同顏色應該如何維護?

考慮對於每一種顏色,如果有兩個該顏色的點同時出現,則相當於將這兩個點的權值分別加\(1\),而把它們\(lca\)的權值減\(1\)。

則我們按照深度,對於每種顏色依次加入該顏色節點\(x\),用\(set\)維護,找出其在\(dfs\)序中的前驅\(pre\)和後繼\(nxt\)。

然後,在主席樹上\(dep_x\)這一版本中,將\(x\)這點本身權值加\(1\),將\(lca(x,pre)\)和\(lca(x,nxt)\)兩點權值減\(1\),並將\(lca(pre,nxt)\)這一點權值加\(1\)。

詢問時只要求出\(dfs\)序中這段區間的權值和即可。

#include#define tp template#define ts template#define reg register

#define ri reg int

#define con const

#define ci con int&

#define i inline

#define w while

#define n 100000

#define ln 20

#define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)

#define swap(x,y) (x^=y^=x^=y)

using namespace std;

int n,d,ee,a[n+5],fa[n+5][ln+1],dep[n+5],di[n+5],do[n+5],d[n+5],lnk[n+5];

struct data

tp i void read(ty& x)

tp i void write(ty x)

tp i void writeln(con ty& x)

i void clear()

#undef d

}f;class chairmantree//主席樹

o[n*ln<<2];

i void ins(ci l,ci r,int& rt,ri lst,ci x,ci t)//插入

i int qry(ci l,ci r,ci rt,ci tl,ci tr)//詢問

public:

i void clear() //清空

i void insert(ci v,ci ov,ci x,ci t)

i int query(ci v,ci l,ci r)

}c;i void dfs(ci x)//dfs遍歷預處理lca和dfs序

i int lca(ri x,ri y)//倍增求lca

int main()

ans=0;w(qtot--) f.read(x),f.read(y),x^=ans,y^=ans,f.writeln(ans=c.query(dep[x]+y,di[x],do[x]));//主席樹上求和

}return f.clear(),0;

}

主席樹 BZOJ 4771 七彩樹

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

BZOJ 4771 主席樹 倍增 set

思路 但是發現這樣怎麼去維護lca呢.因為要求有序,所以我們可以用set來維護相同顏色的節點.如果把乙個點加入集合之後這個點前驅為x,後繼為y,那麼我們去修正,把xy的lca 1,然後x和當前點的lca 1,當前點和y的lca 1.from neighthorn by siriusren inclu...

七彩樹 HYSBZ 4771線段樹合併

本題是查詢乙個節點x的字樹內深度與其相差不超過d的節點有多少種顏色。如果單純考慮有多少個點,應該如何求?此時我們應該考慮如何維護深度在乙個區間內且是x的後代的資訊。我們可以每個節點用一顆以下標為權值的線段樹來維護 後面記為線段樹x 用線段樹合併來完成所有資訊的處理。但如何查詢深度在乙個區間裡的資訊呢...