題意:給出乙個長為 n 的數列,以及 n個操作,操作涉及區間加法,詢問區間內小於某個值 x的元素個數。
思路:這裡有兩種操作,一種是區間加法,這在上一部落格已經介紹過了,不會的戳這裡,還有一種是區間查詢,因為每次查詢的數字都是不一樣的,所以要想時間最優化,必須要排序,因為排序後的查詢操作可以達到log的複雜度。
這裡運用hzwer大牛的話:
我們先來思考只有詢問操作的情況,不完整的塊列舉統計即可;而要在每個整塊內尋找小於乙個值的元素數,於是我們不得不要求塊內元素是有序的,這樣就能使用二分法對塊內查詢,需要預處理時每塊做一遍排序,複雜度o(nlogn),每次查詢在√n個塊內二分,以及暴力2√n個元素,總複雜度o(nlogn + n√nlog√n)。
有乙個小細節,關於block應該開多大,這裡因為用來vector,所以vector存的元素越多對時間越不利。
第一組是0.5n−
−√n
,第二組是n−
−√n
,第三組是2n−
−√n
可以很明顯看到,時間複雜度的優化還是很明顯的。
#include
using
namespace
std;
const
int maxn = 5e4 + 5;
typedef
long
long ll;
int n, num, block, belog[maxn], opt, l, r, c;//belog[i]=j,表示a[i]屬於第j個分塊
int a[maxn], sum[maxn] ;//sum是整塊的加法標記
vector
v[maxn];//用於排序
inline
int read()
void reset(int x)
sort(v[x].begin(), v[x].end());
}void updata(int l, int r, int c)
reset(t2);//對最後乙個區間排序
}for(int i = t1 + 1; i <= t2 - 1; i++) sum[i] += c;//對整塊加上加法標記
}void query(int l, int r, ll c)
if(t1 != t2)
for(int i = t1 + 1; i <= t2 - 1; i++)
}printf("%d\n", ret);
}int main()
for(int i = 1; i <= belog[n]; i++)
for(int j = 1; j <= n; j++)
return
0;}
loj 6278 數列分塊入門 2
題目 區間修改,詢問區間小於c的個數。分塊排序,用vector。至於那個塊的大小,好像要用到均值不等式 我不太會。就開始乙個個試,發現siz sqrt n 4時最快!明天去學一下算分塊複雜度的方法。include include include include include using names...
LOJ 6278 數列分塊入門 2
記憶體限制 256 mib時間限制 500 ms標準輸入輸出 題目型別 傳統評測方式 文字比較 上傳者 hzwer 提交提交記錄 統計討論 測試資料 題目描述 給出乙個長為 nnn 的數列,以及 nnn 個操作,操作涉及區間加法,詢問區間內小於某個值 的元素個數。輸入格式 第一行輸入乙個數字 nnn...
LOJ 6278 數列分塊入門 2
解題思路 分塊維護區間遞增序列。對於修改,邊界暴力後修改兩個邊界的遞增串行使其正確,完整塊打標記 對於詢問,邊界暴力 塊內二分 修改的複雜度 o sqrt n 2 sqrt n log sqrtn 詢問複雜度 o sqrt n 2 sqrt n 所以整體大概是 o q sqrt n log sqrt...