[国家集训队]矩阵乘法
题目描述
给你一个 \(n \times n\) 的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第 \(k\) 小数。
输入格式
第一行有两个整数,分别表示矩阵大小 \(n\) 和询问组数 \(q\)。
第 \(2\) 到第 \((n + 1)\) 行,每行 \(n\) 个整数,表示这个矩阵。第 \((i + 1)\) 行的第 \(j\) 个数表示矩阵第 \(i\) 行第 \(j\) 列的数 \(a_{i, j}\)。
接下来 \(q\) 行,每行五个整数 \(x_1, y_1, x_2, y_2, k\),表示一组询问,要求找到以 \((x_1, y_1)\) 为左上角,\((x_2, y_2)\) 为右下角的子矩形中的第 \(k\) 小数。
输出格式
对于每组询问,输出一行一个整数表示答案。
样例 #1
样例输入 #1
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3
样例输出 #1
1
3
提示
数据规模与约定
- 对于 \(20\%\) 的数据,保证 \(n \leq 100\),\(q \leq 10^3\)。
- 对于 \(40\%\) 的数据,保证 \(n \leq 300\),\(q \leq 10^4\)。
- 对于 \(60\%\) 的数据,保证 \(n \leq 400\),\(q \leq 3 \times 10^4\)。
- 对于 \(100\%\) 的数据,保证 \(1 \leq n \leq 500\),\(1 \leq q \leq 6 \times 10^4\),\(0 \leq a_{i, j} \leq 10^9\)。
题解
整体二分,值域上二分
有点卡常,开O2,同时值域替换为所有数离散化后的数组上二分。
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int f=1,j=0;
char w=getchar();
while(!isdigit(w)){
if(w=='-')f=-1;
w=getchar();
}
while(isdigit(w)){
j=j*10+w-'0';
w=getchar();
}
return f*j;
}
const int N=510,M=60010,K=250010;
int n,m,cnt,ans[M],sum[N][N],tr[N][N];
struct node1{
int lx,ly,rx,ry,k,id;
}que[M],Mid[M];
struct node2{
int x,y,z;
}poi[K];
inline int lowbit(int x){return x&-x;}
inline void add(int x,int y,int z){
for(int i=x;i<=n;i+=lowbit(i)){
for(int j=y;j<=n;j+=lowbit(j)){
tr[i][j]+=z;
}
}
return ;
}
inline int get(int x,int y){
int ansn=0;
for(int i=x;i;i-=lowbit(i)){
for(int j=y;j;j-=lowbit(j)){
ansn+=tr[i][j];
}
}
return ansn;
}
inline int query(int lx,int ly,int rx,int ry){
return get(rx,ry)-get(lx-1,ry)-get(rx,ly-1)+get(lx-1,ly-1);
}
inline void modify(int l,int r,int k){
for(int i=l;i<=r;i++)add(poi[i].x,poi[i].y,k);
return ;
}
void deal(int l,int r,int L,int R){
if(l>r||L>R)return ;
if(l==r){
for(int i=L;i<=R;i++){
ans[que[i].id]=poi[l].z;
}
return ;
}
int mid=(l+r)/2;
modify(mid+1,r,-1);
// cout<<poi[l].z<<" "<<poi[r].z<<"|"<<poi[mid].z<<"-"<<L<<" "<<R<<":"<<"\n";
int ll=L-1,rr=R+1;
for(int i=L;i<=R;i++){
int k=query(que[i].lx,que[i].ly,que[i].rx,que[i].ry);
// cout<<que[i].lx<<" "<<que[i].ly<<" "<<que[i].rx<<" "<<que[i].ry<<":"<<k<<"\n";
if(k>=que[i].k)Mid[++ll]=que[i];
else Mid[--rr]=que[i];
}
for(int i=L;i<=R;i++)que[i]=Mid[i];
deal(l,mid,L,ll);
modify(mid+1,r,1);
deal(mid+1,r,rr,R);
return ;
}
signed main(){
n=rd(),m=rd();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
poi[++cnt].z=sum[i][j]=rd();
poi[cnt].x=i,poi[cnt].y=j;
}
}
for(int i=1;i<=m;i++){
que[i].lx=rd(),que[i].ly=rd(),que[i].rx=rd(),que[i].ry=rd();
que[i].k=rd(),que[i].id=i;
}
sort(poi+1,poi+1+cnt,[&](node2 a,node2 b){return a.z<b.z;});
modify(1,cnt,1);
// for(int i=1;i<=n;i++){
// for(int j=1;j<=n;j++)cout<<tr[i][j]<<" ";
// cout<<"\n";
// }
// cout<<"all:"<<query(1,1,n,n)<<"\n";
// cout<<get(n,n)<<" "<<get(0,n)<<" "<<get(n,0)<<" "<<get(0,0)<<"\n";
deal(1,cnt,1,m);
for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
return 0;
}
标签:二分,10,P1527,int,题解,矩阵,leq,que,国家集训队
From: https://www.cnblogs.com/T-water/p/17014877.html