莫隊階段小結

2022-04-05 20:14:27 字數 3223 閱讀 3546

首先,為什麼要叫小結呢,因為我只學了一點點,後續可能更多

莫隊是一種離線處理區間問題的神器.答題思路就是你將原數列分成\(\sqrt\)塊,將所有查詢左端點定位,並按照左端點所在的塊進行排序,相同則按照右端點排序

大體就是這個樣子

inline bool cmp(q x,q y)
這樣的話我們每個快內都暴力求

時間複雜度為\(o(m\sqrt)\)

但是還有一種玄學加速方式,十分有用

inline bool cmp(q x,q y)
會快很多.

之後我們每次維護取件區間,和當前左右端點.每次發現不在當前區域內就暴力跳的同時修改資訊

int nowl = 1,nowr = 0;

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

另外注意應當先拓展後收縮,為了該開始改成負數之類的東西。

接下來放幾道例題

莫隊的板子題了,我們維護\(sum_i\)表示\(i\)這個數當前出現了多少次,\(ans\)表示當前出現次數\(>=2\)的數的個數

每次修改時更新\(sum\)和\(ans\),之後統計答案即可

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

const int n = 1e5 + 3;

int a[n],ans[n];

int sum[n];

int n,m,now = 0,bl;

int belong[n],block;

inline int read()

while(isdigit(ch))

return v * c;

}struct qq[n];

inline bool cmp(q x,q y)

inline void add(int x)

inline void del(int x)

int main()

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

return 0;

}

雖然是樹上問題,但是所有的詢問都是針對子樹,我們就可以針對他的尤拉序進行操作.

但是比較棘手的是所有的\(k_i\)可能不相同,

我們就設\(sum_i\)表示\(>=i\)的數的個數

\(val_i\)表示\(i\)的出現次數

每次修改統計即可

答案就是\(sum[k_i]\)

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

const int n = 1e5 + 3;

int n,m;

vector g[n];

int v[n],sum[n],val[n];

int l[n],r[n],c[n];

int belong[n];

int ans[n],tot,cnt,bl;

struct qq[n];

inline int read()

while(isdigit(ch))

return v * c;

}inline void dfs(int x,int f)

r[x] = cnt;

}inline bool cmp(q x,q y)

//sum[i]:>=i的數的種類數

//val[i]:i出現次數

inline void add(int x)

inline void del(int x)

int main()

dfs(1,0);

// cout << "gg" << endl;

// for(int i = 1;i <= n;++i) printf("%d %d\n",l[i],r[i]);cout << "gg" << endl;

bl = sqrt(n);

for(int i = 1;i <= n;++i) belong[i] = i / bl;

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

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

int nowl = 1,nowr = 0;

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

for(int i = 1;i <= m;++i) printf("%d\n",ans[i]);

return 0;

}

這道題和上幾道不大一樣,發現不了區間限制之外,還有值域的限制

我們就用樹狀陣列維護值域

但是這樣的時間複雜度為\(n\sqrtlogn\)

其實跑\(10^5\)是挺虛的,還好題目\(3s\),這道題有\(n\sqrt\)的做法,先咕一咕

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

const int n = 1e5 + 3;

int a[n],ans[n],belong[n];

int ans2[n],ans1[n];

int n,m,bl;

int maxx;

int book[n];

struct qq[n << 1];

struct bit

inline int query(int x)

};bit t1,t2;

inline int read()

while(isdigit(ch))

return v * c;

}inline bool cmp(q x,q y)

//int ans = 0;

inline void add(int x)

inline void del(int x)

int main()

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

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

int nowl = 1,nowr = 0;

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

for(int i = 1;i <= m;++i) printf("%d %d\n",ans1[i],ans2[i]);

return 0;

}

莫隊與分塊精簡小結

我覺得我還要補上帶修莫隊,樹上莫隊等等 先咕著 分塊 引用範圍廣,實現簡潔 注意塊的邊界 一般為 sqrt 分塊。塊中可維護很多東西,維護資訊時從後往前處理。例題 hnoi2010 彈飛綿羊 includeusing namespace std define s x x x inline int r...

莫隊總結 莫隊例題

假設我們已知區間 l,r,需要計算的區間為 l,r,由於 l 和 r分別只能單步轉移,所以需要的時間複雜度為 l l r r 相當於把兩個區間分別看成是平面上的兩個整點p1 l,r 和p2 l,r 兩點之間的轉移開銷為兩點之間的曼哈頓距離。連線所有點的最優方案為一棵樹,那麼整體的時間複雜度就是這棵樹...

莫隊講解 普通莫隊

結束了分塊,我們來講下莫隊。據我所知,莫隊能解決一切區間問題,除了翻轉。因為它就是個暴力 其實這兩者的關係並不大。僅僅是時間複雜度一樣而已。我們把原序列分成 n塊 好像就是這裡相同 這裡說的序列是查詢序列l r,並不是讀入的a i 之後我們把序列排序 按照第一關鍵字為左端點所在的塊的大小,如果相同就...