loj 數列分塊入門 6 9 區間眾數

2022-05-11 16:45:23 字數 2618 閱讀 8976

給出乙個長為\(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...