程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Codeforces 375D 數據結構(好題中的好題, 4解)

Codeforces 375D 數據結構(好題中的好題, 4解)

編輯:C++入門知識

 

題意:給你一棵樹n個點,m次詢問(n=100000,m=100000),每個節點有一種顏色,

每次詢問問你以v節點為根的子樹中 滿足 同一種顏色的個數>=k的 顏色有幾個。

 

方法1:顯然詢問要離線處理,不妨用思維簡單的分塊算法處理詢問,

對於每個詢問,我們用數組val[i]表示當前情況下 顏色為i的節點個數

再用val[i]當做下標,用數狀數組維護個數的後綴和,

每次修改一個點 樹狀數組裡面更新2次, 總體復雜度O(sqrt(n)*n*log(n));

 

方法2: 其實也算方法1的優化, 不同之處只是用一個數組維護後綴和,

我們發現 每次修改無非就是把val[i]加一或者減一,不妨用數組sum表示要求的答案

加1:唯一改變的是 val[i]+1的答案, 這個答案要加1, 即sum[++val[i]]++;

減1:唯一改變的是 val[i]的答案, 這個答案要減1, 即sum[val[i]--]--;

總體復雜度O(sqrt(n)*n);

 

方法3:啟發式合並, 詢問按節點v分類,從葉子節點不斷合並,注意這裡一定要把小的堆合並到大的堆裡面,

每個子樹用一個平衡樹維護(這裡我用了treap),用另外一個平衡樹維護每個節點u為根的子樹的所有顏色個數

(我用了map)合並過程就是把兩棵平衡樹合並, treap裡面維護的是val[i],要求答案只要算一下後綴和就可以了

總體復雜度O(n*log^2(n))

方法4: 分治思想, 同樣詢問按節點v分類, 想想暴力的做法處理詢問,用一個全局的數組維護答案,發現O(n^2)可做

但是會超時, 我們可以做個優化, 對於根u 處理 其子樹v1,v2,v3....時, 我們算子樹答案的時候,

把v1子樹放到答案數組裡, 算完以後清空v1子樹, 然後在重復v2,v3....., 注意到最後一個子樹沒有必要清空,

算完最後一個v後dfs會回溯到上一層,去算上一層的答案,而上一層一定包含了v子樹, 清空了反而復雜度會大大提升,

所以我們當然是把子樹規模最大的放到最後去處理比較優秀,這裡類似熟練剖分的重鏈,

每次把子樹加進來和刪除另外寫兩個dfs暴力加減,這樣平均下來每個點被添加和刪除的次數就不會超過log(n),

這樣一來總體復雜度為O(n*log(n))

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved