e 倉鼠與珂朵莉
主席樹 + 啟發式合併思想
題意:
給你乙個長度為n的陣列, 每次操作選擇乙個區間 [l,
r]
[l, r]
[l,r
] 然後問 選擇乙個數 k
kk 然就出 k
kk 再這個區間的次數的乘積。
題解:
如果給你乙個區間[l,
r]
[l, r]
[l,r
] 對於暴力的求法一般是列舉每個數, 再去查詢這個數出現了幾次,然後算出最大的貢獻。
這樣對於每次詢問都是 o(n
)o(n)
o(n)
的複雜度。
如果我們每次只找 出現一次 且最大的數, 出現兩次且最大的數, 出現三次且最大的數…………
假設已經知道看出現一次且最大的數, 出現兩次且最大的數…………
那麼列舉的時間複雜度為 1+2
+3+4
…………
=r−l
+1
1 + 2 + 3 + 4 ………… = r - l + 1
1+2+3+
4………
…=r−
l+1 大概是 (lo
gn)2
(logn)^2
(logn)
2 左右,但是這樣有個問題?
如何找到出現一次且最大的數, 出現兩次且最大數?
我想了很久好像沒有可行的方法。
但是, 仔細想一下, 你會發現, 如果最大值出現了 x
xx 次也就意味著小於 x
xx 次的就不用再找,那麼也就意味著
找 第乙個比 最大值小 且 出現次數大於 x
xx 次的數。
那麼這樣每次的複雜度就是 x
1 ………… x1 < x2 < x3 < x4 ………… x1………… (x 1x1 x1表示最大值出現的次數 x2x2 x2表示第乙個比最大小的數出現的次數…………) 每次尋找都比之前的大,是不是啟發式合併的複雜度啊, 哦好像是的 那麼怎麼找到這個每個數出現的次數呢? 這裡可以用到主席樹了 主席樹沒法確定單個數字出現的個數只能求出這個區間有多少個數, 當這個區間的總個數都小於 x1x1 x1那麼肯定沒有單點資訊大於 x1x1 x1, 在維護乙個每個數 在 [1, r] [1, r] [1,r ] 區間出現的 重要程度的最大值, 如果區間重要程度的最大值都小於 直接找的答案也就沒用必要再找, 這樣兩個限制大概率保證了每個數出現的個數了。 所以總共的時間複雜度為 q∗l og(n )∗lo g(n) q * log(n) * log(n) q∗log( n)∗l og(n ) using namespace std; const int n = 1e5+7; typedef long long ll; struct hjttree[ 40* n] ;vector g; intget_id (int x) ll a[n] , n, q, b[n] ;int rt[n] , top =1; #define m (l + r) / 2 void update (int pos, int l, int r, int last, int&now) if(pos <= m) update (pos, l, m, tree[now] .l, tree[now] .l); else update (pos, m + 1, r, tree[last] .r, tree[now] .r); tree[now] .sum = max(tree[tree[now] .l].sum, tree[tree[now] .r].sum);} ll mx =0; ll ans =0; void query (int last, int now, int l, int r) int sumr = tree[tree[now] .r].cnt - tree[tree[last] .r].cnt; int suml = tree[tree[now] .l].cnt - tree[tree[last] .l].cnt; if(sumr > mx && ans < tree[tree[now] .r].sum) if(suml > mx && ans < tree[tree[now] .l].sum) }int main() sort (g.begin() , g. end()) ; g. erase (unique (g.begin() , g. end()) );for( int i = 1; i <= n; i++ )int maxn = g. size() ;for (int i = 1; i <= n; i++ ) ll last =0; while (q-- )} 題目很簡單,兩個for迴圈巢狀一下,控制下每行左後一位的換行直接輸出就好了。include include include include include includeusing namespace std typedef long long ll typedef unsigned long lo... 一看這題就會想到應該是用線段樹處理 一條邊的分出來的兩個部分點編號並不是連續的,這樣很難用線段樹處理 所以我們就想到給點重新編號,dfs一次,按訪問到的點順序給點編號 dfs一條邊的子樹得到的編號肯定是連續,然後我們記錄著這個居間 這樣就可以套線段樹了,by hehele include inclu... a 時間統計 某個實驗需要統計時間,記錄了實驗開始和結束的時間,計算實驗用了多少秒。第一行輸入乙個整數n,表示樣例個數。接下來每組樣例兩行,表示開始時間和結束時間,格式為xdayhh mm ss,x是乙個整數表示第幾天,0 x 20000,hh表示小時,mm表示分鐘,ss表示秒,保證時間合法,結束時...#include
浙江中醫藥大學2018級新生程式設計競賽
2023年廣東省大學生程式設計競賽 H
2023年湘潭大學程式設計競賽