國家集訓隊 矩陣乘法

2021-08-17 22:46:25 字數 2798 閱讀 5593

–> 洛谷 p1527 <–

這是一道整體二分的經典題目。

這道題顯然可以給每個詢問二分答案,統計該詢問矩陣中小於等於mid的元素個數。如果大於等於k,說明猜大了,否則說明猜小了。

如果用這種方法的話,對於每個詢問都至少要用o(詢問矩陣大小*log值域)的時間複雜度解決,多組詢問的話時間不能接受。

發現多個詢問的二分答案是可以同時被檢驗的,我們可以為所有詢問同時二分答案,把所有答案小於等於mid的詢問放在詢問序列的左側,大於mid的放到詢問序列的右側然後遞迴處理。

這樣為什麼會快呢?我們每次可以用把矩陣中小於等於mid的元素染成黑色,剩下的元素保持白色。這樣對於每乙個詢問的檢驗,就相當於是統計某個子矩陣中黑點的個數。為什麼不用二維樹狀陣列維護字首和呢?

最開始的時候整個矩陣都設為0,然後讓所有小於等於mid的位置加1,o(

n2log2n)

o (n

2log2⁡

n)

處理完整個矩陣之後再o(

log2

n)o (l

og2n

)去應付每乙個詢問。被詢問的子矩陣中可能有很多重疊的部分,這樣保證了在每次詢問過程中,矩陣中的每個元素只對執行時間做一次貢獻,所以這個演算法要比對於每個詢問單獨二分要快得多。

這樣做的時間複雜度為什麼是對的呢?我們是在二分值域,考慮二分過程中的每一層對答案的貢獻。

對於每一層二分,矩陣中的每個元素最多被加入樹狀陣列一次。

對於每一層二分,每個詢問只會被處理一次。

二分值域的過程中最多隻會出現o(

logn

) o

(log⁡n

)層。時間複雜度o(

(n2+

q)log3n)

o ((

n2+q

)log3⁡

n)

,感覺這時間複雜度不開o2過不了啊,想要不開o2 ac可能得大力卡常一發。

發表一下個人見解:感覺cdq分治和整體二分有異曲同工之妙,是同一種分治思想在不同維度發揮作用的體現。(之所以這麼說是因為**寫起來是非常像的。)

還有一點,不要真的去二分值域,不然還得需要離散化,常數更大。把矩陣中的所有元素按照權值排序,二分在答案在排序之後的陣列中的位置即可。(因為答案一定是矩陣中存在的值,所以在這些值裡面二分就好了。)

給出**:

// luogu-judger-enable-o2

#include

#include

#include

#include

using

namespace

std;

inline

int geti()

inline

void puti(int x)

const

int maxn = 500 + 10, maxq = 60000 + 5;

struct numbers

} matrix[maxn * maxn]; int mcnt; /// 矩陣中的元素個數

struct bit /// 初始化

inline

int lowbit(int x)

inline

void add(int x, int y, int v)

inline

int pre(int x, int y)

inline

int submat(int x1, int y1, int x2, int y2)

} bit; /// 記得初始化 n

struct events

} querys[maxq];

int bcount(events mat)

int id[maxq], t1[maxq], t2[maxq];

int ans[maxq], cur[maxq];

void sol(int l, int r, int ql, int qr)

int mid = (l + r)/2;

for(int i = l; i <= mid; i ++) /// 把要統計到答案中的數值染黑

bit.add(matrix[i].x, matrix[i].y, 1);

int cnt1 = 0, cnt2 = 0;

for(int i = ql; i <= qr; i ++)

int qcnt = ql - 1;

for(int i = 1; i <= cnt1; i ++) id[++ qcnt] = t1[i]; /// 左右分組

for(int i = 1; i <= cnt2; i ++) id[++ qcnt] = t2[i];

for(int i = l; i <= mid; i ++) /// 誰汙染誰治理

bit.add(matrix[i].x, matrix[i].y, -1);

sol(l, mid, ql, ql + cnt1 - 1);

sol(mid+1, r, ql + cnt1, qr);

}int main() ;

sort(matrix + 1, matrix + mcnt + 1); /// 按元素大小從小到大排序

for(int i = 1; i <= q; i ++) querys[i].input();

for(int i = 1; i <= q; i ++) id[i] = i;

sol(1, mcnt, 1, q);

for(int i = 1; i <= q; i ++) puti(ans[i]), putchar('\n');

return

0;}

Luogu P1527 國家集訓隊 矩陣乘法

給定乙個 n n n times n n n 的矩陣,對於 q qq 組 x1,y1,x 2,y2 k x1,y1,x2,y2,k x1,y1,x2,y 2,k,你需要求出該子矩陣內的第 k kk 大的值。資料範圍1 n 500,1 q 60000 1 leqslant n leqslant 500...

整體二分 國家集訓隊 矩陣乘法

題目描述 給你乙個 n times nn n 的矩陣,不用算矩陣乘法,但是每次詢問乙個子矩形的第 kk 小數。輸入格式 第一行有兩個整數,分別表示矩陣大小 nn 和詢問組數 qq。第 22 到第 n 1 n 1 行,每行 nn 個整數,表示這個矩陣。第 i 1 i 1 行的第 jj 個數表示矩陣第 ...

洛谷 P1527 國家集訓隊 矩陣乘法

矩陣第k小 一道練習整體二分的比較好的題 這道題把序列查詢區間第 k 小搬到了矩陣上,但是仍然滿足二分性質,所以我們還是可以整體二分 而我們沿用序列上的做法,把點和詢問都離線下來,揉在一起整體二分 唯一不一樣的地方就是需要二維樹狀陣列,這個很好理解吧qwq 複雜度 o qlog 3n code in...