首先,為什麼要叫小結呢,因為我只學了一點點,後續可能更多
莫隊是一種離線處理區間問題的神器.答題思路就是你將原數列分成\(\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 之後我們把序列排序 按照第一關鍵字為左端點所在的塊的大小,如果相同就...