–> 洛谷 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
(logn
)層。時間複雜度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...