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
)
#include
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--
)}
浙江中醫藥大學2018級新生程式設計競賽
題目很簡單,兩個for迴圈巢狀一下,控制下每行左後一位的換行直接輸出就好了。include include include include include includeusing namespace std typedef long long ll typedef unsigned long lo...
2023年廣東省大學生程式設計競賽 H
一看這題就會想到應該是用線段樹處理 一條邊的分出來的兩個部分點編號並不是連續的,這樣很難用線段樹處理 所以我們就想到給點重新編號,dfs一次,按訪問到的點順序給點編號 dfs一條邊的子樹得到的編號肯定是連續,然後我們記錄著這個居間 這樣就可以套線段樹了,by hehele include inclu...
2023年湘潭大學程式設計競賽
a 時間統計 某個實驗需要統計時間,記錄了實驗開始和結束的時間,計算實驗用了多少秒。第一行輸入乙個整數n,表示樣例個數。接下來每組樣例兩行,表示開始時間和結束時間,格式為xdayhh mm ss,x是乙個整數表示第幾天,0 x 20000,hh表示小時,mm表示分鐘,ss表示秒,保證時間合法,結束時...