洛谷1527 [國家集訓隊]矩陣乘法(整體二分)
題意:給你一個的矩陣,每次詢問一個子矩形的第k小數
輸入格式:第一行有兩個整數,分別表示矩陣大小n和詢問組數q
第2到第(n + 1)行,每行n個整數,表示這個矩陣。第(i + 1)行的第j個數表示矩陣第i行第j列的數ai,j
接下來q行,每行五個整數x1,y1,x2,y2,k,表示一組詢問,要求找到以(x1,y1)為左上角,(x2,y2)為右下角的子矩形中的第k小數
輸出格式:對於每組詢問,輸出一行一個整數表示答案。
#include<cstdio> #include<algorithm> const int N = 505; const int M = 6e4 + 5; struct Matrix{ int x, y, val; bool operator <(const Matrix &u)const{ return val < u.val; } }matrix[N * N]; struct Query{ int x1, y1, x2, y2, k; }q[M]; struct BIT{ int n, m; int c[N][N]; inline void init(int x, int y) { n = x, m = y; } inline intlowbit(int &x) { return x & -x; } void modify(int x, int y, int p){ for(int i = x; i <= n; i += lowbit(i)) for(int t = y; t <= m; t += lowbit(t)){ c[i][t] += p; } } int query(int x,int y){ int ans = 0; for(inti = x; i; i -= lowbit(i)) for(int t = y; t; t -= lowbit(t)){ ans += c[i][t]; } return ans; } int Query(Query p){ return query(p.x2, p.y2) + query(p.x1 - 1, p.y1 - 1) - query(p.x1 - 1, p.y2) - query(p.x2, p.y1 - 1); } }Tree; int n, m, tot; int ans[M], id[M], cur[M], t1[M], t2[M]; void solve(int l, int r, int ql, int qr){ // 二分值域 if(ql > qr) return ; //該值域區間沒有詢問 if(l == r){ for(int i = ql; i <= qr; ++i) ans[id[i]] = matrix[l].val; return ; // 找到解 } int mid = (l + r) >> 1; for(int i = l; i <= mid; ++i) Tree.modify(matrix[i].x, matrix[i].y, 1); int cl = 0, cr = 0; for(int i = ql; i <= qr; ++i){ int u = id[i]; // 當前要處理的詢問 int s = cur[u] + Tree.Query(q[u]); // 加上當前區間中位於q[u]詢問矩陣範圍內的點 if(s >= q[u].k) t1[++cl] = u; else t2[++cr] = u, cur[u] = s; } int kk = ql - 1; for(int i = 1; i <= cl; ++i) id[++kk] = t1[i]; // 左右分組 for(int i = 1; i <= cr; ++i) id[++kk] = t2[i]; for(int i = l; i <= mid; ++i) Tree.modify(matrix[i].x, matrix[i].y, -1); solve(l, mid, ql, ql + cl - 1); solve(mid + 1, r, ql + cl, qr); } int main(){ scanf("%d%d", &n, &m); Tree.init(n, n); for(int i = 1, val; i <= n; ++i) for(int t = 1; t <= n; ++t){ scanf("%d", &val); matrix[++tot] = Matrix{i, t, val}; } std::sort(matrix + 1, matrix + 1 + tot); for(int i = 1; i <= m; ++i) id[i] = i; for(int i = 1; i <= m; ++i) scanf("%d%d%d%d%d", &q[i].x1, &q[i].y1, &q[i].x2, &q[i].y2, &q[i].k); solve(1, tot, 1, m); for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); return 0; }
#include<cstdio>
#include<algorithm>
const int N = 505;
const int M = 6e4 + 5;
struct Matrix{
int x, y, val;
bool operator <(const Matrix &u)const{
return val < u.val;
}
}matrix[N * N];
struct Query{
int x1, y1, x2, y2, k;
}q[M];
struct BIT{
int n, m;
int c[N][N];
inline void init(int x, int y) { n = x, m = y; }
inline int lowbit(int &x) { return x & -x; }
void modify(int x, int y, int p){
for(int i = x; i <= n; i += lowbit(i))
for(int t = y; t <= m; t += lowbit(t)){
c[i][t] += p;
}
}
int query(int x,int y){
int ans = 0;
for(int i = x; i; i -= lowbit(i))
for(int t = y; t; t -= lowbit(t)){
ans += c[i][t];
}
return ans;
}
int Query(Query p){
return query(p.x2, p.y2) + query(p.x1 - 1, p.y1 - 1) - query(p.x1 - 1, p.y2) - query(p.x2, p.y1 - 1);
}
}Tree;
int n, m, tot;
int ans[M], id[M], cur[M], t1[M], t2[M];
void solve(int l, int r, int ql, int qr){ // 二分值域
if(ql > qr) return ; //該值域區間沒有詢問
if(l == r){
for(int i = ql; i <= qr; ++i) ans[id[i]] = matrix[l].val;
return ; // 找到解
}
int mid = (l + r) >> 1;
for(int i = l; i <= mid; ++i) Tree.modify(matrix[i].x, matrix[i].y, 1);
int cl = 0, cr = 0;
for(int i = ql; i <= qr; ++i){
int u = id[i]; // 當前要處理的詢問
int s = cur[u] + Tree.Query(q[u]);// 加上當前區間中位於q[u]詢問矩陣範圍內的點
if(s >= q[u].k) t1[++cl] = u;
else t2[++cr] = u, cur[u] = s;
}
int kk = ql - 1;
for(int i = 1; i <= cl; ++i) id[++kk] = t1[i]; // 左右分組
for(int i = 1; i <= cr; ++i) id[++kk] = t2[i];
for(int i = l; i <= mid; ++i) Tree.modify(matrix[i].x, matrix[i].y, -1);
solve(l, mid, ql, ql + cl - 1);
solve(mid + 1, r, ql + cl, qr);
}
int main(){
scanf("%d%d", &n, &m);
Tree.init(n, n);
for(int i = 1, val; i <= n; ++i)
for(int t = 1; t <= n; ++t){
scanf("%d", &val);
matrix[++tot] = Matrix{i, t, val};
}
std::sort(matrix + 1, matrix + 1 + tot);
for(int i = 1; i <= m; ++i) id[i] = i;
for(int i = 1; i <= m; ++i)
scanf("%d%d%d%d%d", &q[i].x1, &q[i].y1, &q[i].x2, &q[i].y2, &q[i].k);
solve(1, tot, 1, m);
for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
return 0;
}