莫隊演算法 雜湊 csu1515 Sequence

2021-07-03 06:43:32 字數 1492 閱讀 8493

這是中南第二屆邀請賽的題目,當時還不懂莫隊演算法,,現在做起來感覺思路還是挺清晰的,可以用來當莫隊演算法的練習

首先講下莫隊演算法(也是逆天),是一種分塊的思路(超逆天思維)

它是一種離線演算法,複雜度是o(m*sqrt(n)),m是區間範圍大小,n是區間個數

適用條件:如果知道[l,r]的答案,可以用o(1)或者o(logn)的複雜度求出[l-1,r]  [l+1,r]  [l,r-1]  [l,r+1]的答案,那麼就可以用莫隊演算法(幾乎是區間萬能演算法)

大概的思路是,把n個區間分成sqrt(n)塊,求出區間左端點所在的塊,然後排序

先按左端點所在的塊的大小排序,如果相等,再按照右端點的大小排序。如果右端點的大小相等,再按照左端點的大小排序

然後只要按照排序的順序,依次求出每個區間的答案就可以了

莫隊演算法複雜度證明:

設n為區間個數,m為r最大的值

y向右移動的次數,最極端的情況下,每個塊的y都會從1移動到m,一共有sqrt(n)個塊,所以這的複雜度是m*sqrt(n)

y向左移動的次數,只會在跨塊的時候才會出現,一共只會出現sqrt(n)-1次跨塊的情況,假如每次y都是從n向左移動到了1,所以這的複雜度是m*sqrt(n)

x不跨塊移動的次數,l會在1和這個區間長度的交換,記當前區間長度為w,一共sqrt(n)個塊,乙個塊有sqrt(n)個,複雜度w*sqrt(n)*n=w*n,實際上m平均等於sqrt(m)左右,總的複雜度n*sqrt(m)

x跨塊移動,跨塊只有sqrt(n)-1種情況,每次跨塊最多移動兩個區間長

綜上所述,總的複雜度o(m*sqrt(n))

分塊法有很多逆天的作用,莫隊演算法只是其中的一種用法。

#include#include#include#include#include#include#includeusing namespace std;

const int hs=1000007;

const int mx=100000+5;

typedef long long ll;

int num[mx];

int m,n,unit;

ll a[mx],ans[mx];

int head[hs],next[mx];

void hash_create()

}if(sign)

}} int query(ll x)

return 0;}

void update(ll x,int d)

}} struct query

while(rq[i].r)

ans[q[i].id]=s;

}} int main()

hash_create();

for(int i=1;i<=m;i++)

unit=sqrt(n+0.5);

sort(q+1,q+1+m);

work();

for(int i=1;i<=m;i++)

}return 0;

}

CSU 1515 Sequence (莫隊演算法)

題意 給n個數,m個詢問。每個詢問是乙個區間,求區間內差的絕對值為1的數對數。題解 先離散化,然後莫隊演算法。莫隊是離線演算法,先按按詢問左端點排序,在按右端點排序。ps 第一次寫莫隊,表示挺簡單的,不過這題之前亂搞一氣一直tle,莫隊還是很強大的。include include include i...

樹上莫隊演算法

繼續回來寫部落格 記錄點有意思的題目什麼的。貌似寫過這個的沒多少人 所以我也記錄一點。首先序列上的莫隊大家都應該很熟悉了 那麼樹上的莫隊要怎麼搞呢?先來看個題目 spoj cot2 求樹上兩點間路徑上有多少個不同的點權。序列上的莫隊是把詢問按照左端點分塊了 可是樹上沒有左端點,怎麼辦呢?我們把樹分塊...

模板 莫隊演算法

題意 給定乙個大小為n的陣列,陣列中所有元素的大小 n。你需要回答m個查詢。每個查詢的形式是l,r,k。你需要回答在範圍 l,r 中至少重複k次的數字的個數。n,m 100000 誒,這題卡了好久,tle,中間棄了一段,然後今天學弟學莫隊,拿出這個題,他也沒什麼想法,然後我頓時退一步海闊天空了。最開...