1. 程式人生 > 實用技巧 >洛谷1527 [國家集訓隊]矩陣乘法(整體二分)

洛谷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 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; }

#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;

}