約束rmq 約束RMQ

2021-10-13 04:42:46 字數 1960 閱讀 6107

不知道為什麼網上找不到太多相關的資料,所以寫乙個小總結,並附有能用的**,拋磚引玉。

約束rmq,就是rmq區間必須滿足兩項之差最大為1,採用st表的話,這時候有o(n)建表,o(1)查詢的優秀複雜度

求lca,通過dfs把原樹轉化為深度序列,就等價於求區間最小值 (取到的位置)

由於dfs的性質,該序列兩個數之間顯然相差1,所以可以使用約束rmq解決

先總體概括一下做法:把原序列分塊,塊內預處理,塊間做st表

分塊大小定為l=log(n)/2,這樣共分d=n/l塊,對這d個數(塊內最小值)做正常st表,建表複雜度o(dlog(d))=o((n/l)(log(n)-log(l))=o(n)

我們要保證每個步驟都是o(n)的,log(n)/2的塊正好消去了st建表時的log

但在此之前,我們得處理出塊內的最小值,該怎麼做呢?乙個正常想法就是列舉每個數,一共是o(n)複雜度

但是,這樣做雖然留下了每塊的最小值以及其取到的位置,若考慮查詢塊的乙個區間,而這個區間恰好取不到最小值,這時候只能暴力列舉,就破壞了查詢o(1)了

至此我們仍沒有使用其±1的特殊性質,現在考慮一下。

塊內一共log(n)/2個數,由乘法原理可知,本質不同的塊有u=2^(log(n)/2)=n^(1/2)個,我們不妨處理出每個這種塊,複雜度ulog(n)/2,這個函式增長是小於線性的,可以認為是o(n)

這樣,處理出每個塊內兩元素的大小關係,就可以用01唯一表示乙個塊了,可以用二進位制存下來,作為乙個塊的特徵,這一步複雜度o(n)

這樣有乙個好處,即使查詢塊內乙個區間,我們只需要提取這個區間對應的二進位制數,就可以在預處理的陣列中o(1)查詢了

(怎麼做呢?把這段二進位制數提出來,移到最右邊,由於我們規定0表示小於,1表示大於,所以會貪心地選取前面的數,查表減去偏移量就可以了)

查詢時,類似分塊,邊角的塊直接查表,中間部分st表查詢,查詢是o(1)的。

至此我們完成了o(n)建表,o(1)查詢的約束rmq。

一般地,對於任何乙個序列,可以在o(n)時間內建成一顆笛卡爾樹,把查詢該序列rmq轉化為求笛卡爾樹lca,就變成o(1)的了。

想進一步提高速度,可以使用更快的log

int mylog (unsigned intx) ;int l = -1;while (x >= 256) return l +log_2[x];

解決lca的**:

//drunk,fix later

#include#include#include

#define re register

using namespacestd;const int maxn=1000005;

inlineintrd() intn,m,st;structedge e[maxn<<1];intecnt,head[maxn];

inlinevoid add(int x,inty) intblocklen,num,l[maxn],r[maxn],bl[maxn];int blocktyp[maxn],f[maxn][32],g[maxn][32];intlookup[maxn];

inlineint computetype(intx) voidbuild() for(re int i=tot+1; i<=r[num]; i++) dep[i]=(1<<30);for(re int i=1; i<=tot; i++)bl[i]=(i-1)/blocklen+1;for(re int i=0; i*i<=tot; i++) calcpos(i);for(re int i=1; i<=num; i++)blocktyp[i]=computetype(i);for(re int i=1; i<=num; i++) g[i][0]=(i-1)*blocklen+lookup[blocktyp[i]],f[i][0]=dep[g[i][0]]; //offset!

for(re int j=1; (1<

inlineint inblockquery(int x,inty) int query(int x,inty) intmain() return 0;

約束rmq 1RMQ(約束RMQ)

1rmq其實是rmq的乙個特殊情況,它的特殊性體現在 序列中每兩個相鄰元素的差是1或 1。即 對於這種特殊情況,有一種方法可以將rmq的時間降至常數級別,即用 的時間解決。可以發現,如果lca用dfs rmq的方法解決,則rmq部分正好是 1rmq。所以,如果會了這種方法,將可以用 這裡簡單 因為我...

約束RMQ 1RMQ演算法 複雜度O n

約束rmq的解法 現在仍舊用a 0,n 1 表示問題中的數列,這裡有 a i a i 1 1 i 1,2,n 1 成立。將a分解為長度為l log n 2 的塊。設a i 為第i塊中的最小值,b i 為該最小值的位置。a i 和b i 的長度均為n l,所以用st演算法處理a 陣列的時空複雜度均為o...

RMQ 超級鋼琴

超級鋼琴 超級鋼琴 問題描述 小z 是乙個小有名氣的鋼琴家,最近 c 博士送給了小z一架超級鋼琴,小 z 希望能夠用這架鋼琴創作出世界上最美妙的 這架超級鋼琴可以彈奏出 n個音符,編號為 1至n。第i個音符的美妙度為 ai,其中ai可正可負。乙個 超級和弦 由若干個編號連續的音符組成,包含的音符個數...