牛客練習賽30 F 小K種妹妹(樹上分塊)

2021-08-31 07:45:29 字數 1812 閱讀 9037

大致題意,實現一種樹狀資料結構,包含修改權值,新增節點,刪除邊和查詢子樹內特定權值範圍節點個數的操作。

雖然說是資料結構,而且有lct這個東西可以考慮使用,但是分塊作為一種非常快速的方法著實是賽場上的首選。樹上的分塊相對比較少見,本題可以作為樹上分塊的模板題。

樹上分塊與普通分塊類似,只不過是要按照dfs序去分塊。每次順序dfs,把節點加入塊中,當塊的節點個數大於閾值,那麼開闢新的塊。如果樹中間存在節點連線兩個塊,那麼對應就要有一條邊連線這兩條塊。可以預見,當分塊完畢之後,原本乙個含n個節點的樹,會變成乙個只含有大約

當我們需要查詢時,首先在塊的級別上查詢,到臨界點的時候再在普通節點的級別上查詢。如此,當閾值設定的好的時候,我們查詢的時間複雜度就是o(

對於刪除邊的操作也是類似。我們分刪除邊是塊間邊和塊內邊兩種情況。當是塊間邊的時候,相對比較容易處理,直接把原本塊級別上的邊刪除即可,不需要過多的維護塊節點的數值。而當是塊內邊的時候,由於一條邊的刪除,原本的乙個塊會分成兩個塊,在刪除一條邊的同時,要維護兩個塊節點的數值。

針對本題來說,需要維護在一定數值範圍內的點的個數,我們只需要對於每乙個塊,動態維護乙個vector即可。每一次塊內查詢的時候二分查詢即可。本題總的複雜度是o(n

#include#define inf 0x3f3f3f3f

#define pi 3.141592653589793

#define mod 998244353

#define ll long long

#define pb push_back

#define lb lower_bound

#define ub upper_bound

#define sf(x) scanf("%d",&x)

#define sc(x,y,z) scanf("%d%d%d",&x,&y,&z)

using namespace std;

const int n = 200010;

struct blocks

inline void update(int x,int y)

inline void erase(int x)

inline void insert(int x)

inline int query(int x)

} blks[n];

int blk,tot,n,q,w[n],f[n],fa[n];

int ls[n],g[n<<1],nxt[n],e=0;

int ls[n],g[n<<1],nxt[n],e=0;

inline void addedge(int x,int y)

inline void addedge(int x,int y)

void build(int x,int father)

}int blk_query(int x,int lim)

int query(int x,int lim)

return res;

}void cut(int x,int ff)

addedge(ff,y);}}

blks[f[x]=ff].insert(w[x]);

}int main()

else if (fa[x])

} else cut(x,x);

fa[x]=0; }}

return 0;

}

牛客練習賽30

眾所周知,小k是nowcoder的 苟管理,所以小k很擅長踢樹,雖然本題與踢樹無關 小k喜歡將日期排列成yyyy mm dd的形式 位數不足添零補齊 的形式,雖然這與小k只會做回文字串這道水題無關,但小k覺得日期組成的回文串也是挺可愛的。作為乙個涼心出題人,小k決定給你乙個可愛的問題 給你兩個日期,...

牛客練習賽58 F

求帶單點修改的樹上兩點間任意子路徑長異或和。路徑長等於路徑上所有異或和。簡單模擬一下,可以發現。奇數情況下,答案是偶數點異或和。偶數情況下,就是正常的異或和。偶數點異或和也很容易處理。分深度奇偶樹狀陣列即可。但是這是對於鏈的,不能直接dfs dfsdf s序,需要剖分一下。但是我不會,所以去學了一下...

(補題)牛客小白月賽30 F 石子合併(貪心)

鏈結 題目 牛牛有 n 堆石子,每堆石子有 a i 個,牛牛每次可以選擇相鄰的兩堆石子,然後拿走少的那一堆,得到的價值是兩堆石子個數之和,直到只剩下一堆石子。如果拿走了第 i 堆石子,那麼第 i 1 堆和第 i 1 堆 就會相鄰。牛牛想知道該怎麼拿,才能使得到的價值最多。輸入 第一行乙個整數 n,1...