給出乙個長為\(n\)的數列,以及\(n\)個操作,操作涉及單點插入,單點詢問,資料隨機生成。
參考:每個塊內用乙個\(vector\)維護,每次插入時先找到位置所在的塊,再暴力插入。
如果資料不隨機,即如果先在乙個塊有大量單點插入,這個塊的大小會大大超過\(\sqrt n\),那塊內的暴力就沒有複雜度保證了。
為此引入乙個操作:重新分塊(重構)
每\(\sqrt n\)次插入後,重新把數列平均分一下塊,重構需要的複雜度為\(o(n)\),重構的次數為\(\sqrt n\),所以重構的複雜度沒有問題,而且保證了每個塊的大小相對均衡。
當然,也可以當某個塊過大時重構,或者只把這個塊分成兩半。
// **中採取的是當塊過大時進行重構。
#include #define maxn 200010
#define c 20
#define f(i, a, b) for (int i = (a); i < (b); ++i)
#define f2(i, a, b) for (int i = (a); i <= (b); ++i)
#define df(i, a, b) for (int i = (a); i > (b); --i)
#define df2(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long ll;
int n, blo, a[maxn], num;
vectorv[510];
struct node ;
node query(int p) ;
}void rebuild()
blo = sqrt(cnt); num = (cnt+blo-1)/blo;
f(i, 0, cnt) v[i/blo].push_back(a[i]);
}void insert(int p, int x)
int main()
num = (n+blo-1)/blo;
f(i, 0, n)
else insert(l, r);
}return 0;
}
給出乙個長為\(n\)的數列,以及\(n\)個操作,操作涉及詢問區間的最小眾數。
參考:離散化。
對每乙個數開乙個桶,即對每個數用乙個\(vector\)按序記錄它所有的出現位置。
預處理出\(f[s][t]\)表示第\(s\)塊到第\(t\)塊的最小眾數:
方法是:列舉\(s\),向右掃,每掃乙個塊得到乙個值。
複雜度:\(\sqrt n*\sqrt n+(\sqrt n-1)*\sqrt n+\cdots+2*\sqrt n+\sqrt n=\sqrt n*(1+2+\cdots+\sqrt n)=o(n\sqrt n)\)
對於乙個詢問\([l,r]\):
不完整的塊中共有\(2\sqrt n\)個數,完整的塊根據3. 中的預處理得到乙個數。
暴力比較這\(2\sqrt n+1\)個數的出現次數,
方法是:要知道\(x\)在\([l,r]\)中的出現次數,只需在\(vector[x]\)中進行二分查詢。
複雜度:\(o(\sqrt n*logn)\)
#include #define f(i, a, b) for (int i = (a); i < (b); ++i)
#define f2(i, a, b) for (int i = (a); i <= (b); ++i)
#define df(i, a, b) for (int i = (a); i > (b); --i)
#define df2(i, a, b) for (int i = (a); i >= (b); --i)
#define maxn 100010
#define inf 0x3f3f3f3f
using namespace std;
int cnt[maxn], a[maxn], n, num, blo, f[1010][1010], bl[maxn], mp2[maxn];
mapmp;
vectorv[maxn];
typedef long long ll;
inline void update(int temp, int& maxx, int x, int& ans)
}void pre(int s)
f[s][i] = ans;
}}inline int count(int l, int r, int x)
int query(int l, int r)
if (bl[l]!=bl[r])
}if (bl[l]+1<=bl[r]-1)
return ans;
}int main()
bl[i] = i/blo;
v[a[i]=mp[a[i]]].push_back(i);
}num = bl[n-1]+1;
f(i, 0, num) pre(i);
f(i, 0, n)
return 0;
}
LOJ 6285 數列分塊入門 9 區間眾數
如果只查詢眾數的個數,完全可以莫隊,加數時容易維護眾數的數量,刪除數時,眾數的數量要麼減1,要麼不變,只需再開乙個標記陣列維護眾數的數量即可 根據陳立傑 區間眾數解題報告 實現了下面兩種解法 解法一 塊數分成sqrt n 超時了,150可以過 分塊真毒瘤 pragma gcc optimize 2 ...
數列分塊入門9 區間眾數
原題 題解 基本題意求 l,r 的最小眾數,對於集合 a,b 顯然 mode a and b 屬於 mode a and b。這樣就可以分塊,預處理f i j 表示i j的眾數。每次查詢時暴力查詢頭尾兩塊的數和中間塊的眾數就可以,關於查詢x在 l,r 出現了幾次,用動態陣列存放x的下標,二分查詢就好...
數列分塊入門7 區間標記下放
原題 題解 本題大意 區間加法,乘法,單點查詢,設sum為塊的加法標記,mul為乘法標記。通過分析有 include define reg register define ll long long const int n 110000,mm 550,m 10007 using namespace s...