Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
矩阵中数字是109以内的非负整数;
20%的数据:N<=100,Q<=1000;
40%的数据:N<=300,Q<=10000;
60%的数据:N<=400,Q<=30000;
100%的数据:N<=500,Q<=60000。
Solution
作为一个主席树/树套树爱好者表示这道题主席树写起来非常爽
但是如果是主席树做法就没啥好讲了,于是写了cdq分治的做法
一个非常容易想到的办法就是二分一个mid,用树状数组统计子矩阵中插入数字的数量
一开始错了是输出把T打成了n,( ╯□╰ )
好像也没啥好讲的。。。
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define lowbit(x) ((x)&(-(x)))
const int N=605;
const int G=80005;
struct Q {int x1,y1,x2,y2,k,id,ans;} q[G],tmp[G];
struct data {int x,y,w;} a[N*N];
int c[N][N],rec[G];
int now,tot,n;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void add(data a,int v) {
for (int i=a.x;i<=n;i+=lowbit(i)) {
for (int j=a.y;j<=n;j+=lowbit(j)) {
c[i][j]+=v;
}
}
}
int get(int x,int y) {
int ret=0;
for (int i=x;i;i-=lowbit(i)) {
for (int j=y;j;j-=lowbit(j)) {
ret+=c[i][j];
}
}
return ret;
}
void solve(int l,int r,int L,int R) {
if (l>r) return ;
if (L==R) {
rep(i,l,r) q[i].ans=L;
return ;
}
int mid=(L+R)>>1;
for (;now<tot&&a[now+1].w<=mid;) add(a[++now],1);
for (;now&&a[now].w>mid;) add(a[now--],-1);
int cnt=0;
rep(i,l,r) {
int res=get(q[i].x2,q[i].y2)+get(q[i].x1-1,q[i].y1-1);
res=res-get(q[i].x2,q[i].y1-1)-get(q[i].x1-1,q[i].y2);
if (res>=q[i].k) {
cnt++; rec[i]=1;
} else rec[i]=2;
}
int tl=l,tr=l+cnt;
rep(i,l,r) if (rec[i]==1) tmp[tl++]=q[i];
else tmp[tr++]=q[i];
rep(i,l,r) q[i]=tmp[i];
solve(l,l+cnt-1,L,mid);
solve(l+cnt,r,mid+1,R);
}
bool cmp1(data a,data b) {
return a.w<b.w;
}
bool cmp2(Q a,Q b) {
return a.id<b.id;
}
int main(void) {
n=read(); int T=read();
rep(i,1,n) rep(j,1,n) a[++tot]=(data) {i,j,read()};
std:: sort(a+1,a+tot+1,cmp1);
rep(i,1,T) q[i]=(Q) {read(),read(),read(),read(),read(),i};
solve(1,T,1,a[tot].w);
std:: sort(q+1,q+T+1,cmp2);
rep(i,1,T) printf("%d\n", q[i].ans);
return 0;
}