解法
整体二分
首先有一个显然的对于每组询问都二分答案,然后
O
(
n
2
)
O(n^2)
O(n2)查询询问矩阵的做法。
在此基础上,本来笔者想要用主席树的在线算法解决问题,但是复杂度是
O
(
q
n
l
o
g
2
n
)
O(qnlog^2n)
O(qnlog2n),不能通过,随即考虑整体二分。
整体二分的思路是将所有操作放在一起处理,一次性把所有询问的答案处理出来。
考虑本题,将矩阵内的每个值当作一次赋值操作,然后用二维树状数组维护,每次询问的时候考虑当前答案下询问矩阵中的数是否已经大于k,满足要求的放在左边,不满足的放在右边。
代码思路其实比较简单。
#include<bits/stdc++.h>
using namespace std;
const int maxn=505,maxq=6e4+5;
inline int read(){
char c=getchar();int t=0,f=1;
while((!isdigit(c))&&(c!=EOF)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)&&(c!=EOF)){t=(t<<3)+(t<<1)+(c^48);c=getchar();}
return t*f;
}
int n,m;
struct que{
int x1,y1,x2,y2,v,id;
que(int _x1=0,int _y1=0,int _x2=0,int _y2=0,int _v=0,int _id=0){
x1=_x1,y1=_y1,x2=_x2,y2=_y2,v=_v,id=_id;
}
}q[maxn*maxn+maxq],q1[maxn*maxn+maxq],q2[maxn*maxn+maxq];
int tot;
int c[maxn][maxn];
#define lowbit(x) x&(-x)
int ans[maxq];
const int inf=1e9+7;
inline void add(int x,int y,int val){
for(int i=x;i<=n;i+=lowbit(i))
for(int j=y;j<=n;j+=lowbit(j))c[i][j]+=val;
}
inline int query(int x,int y){
int ans=0;
for(int i=x;i;i-=lowbit(i))
for(int j=y;j;j-=lowbit(j))ans+=c[i][j];
return ans;
}
inline int query_a(int x1,int y1,int x2,int y2){
return query(x2,y2)-query(x2,y1-1)-query(x1-1,y2)+query(x1-1,y1-1);
}
void solve(int l,int r,int L,int R){//[l,r]:值域,[L,R]:处理的操作区间
/*printf("%d %d %d %d\n",l,r,L,R);
for(int i=L;i<=R;i++){
printf("%d %d\n",q[i].id,q[i].v);
}*/
if(L>R)return ;
if(l==r){
for(int i=L;i<=R;i++){
if(q[i].id)ans[q[i].id]=l;
}
return ;
}
int mid=(l+r)>>1;
int l1=0,l2=0;
for(int i=L;i<=R;i++){
if(!q[i].id){
if(q[i].v<=mid){
add(q[i].x1,q[i].y1,1);
// printf("%d %d\n",q[i].x1,q[i].y1);
q1[++l1]=q[i];
}
else{
q2[++l2]=q[i];
}
}
// printf("%d %d\n%d %d\n",query(1,1),query(1,2),query(2,1),query(2,2));
}
for(int i=L;i<=R;i++){
if(q[i].id){
int tmp=query_a(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
if(tmp>=q[i].v){
q1[++l1]=q[i];
}
else{
q[i].v-=tmp;
q2[++l2]=q[i];
}
}
}
for(int i=1;i<=l1;i++)if(!q1[i].id)add(q1[i].x1,q1[i].y1,-1);
for(int i=L;i<L+l1;i++){
q[i]=q1[i-L+1];
}
for(int i=L+l1;i<=R;i++){
q[i]=q2[i-L-l1+1];
}
solve(l,mid,L,L+l1-1);
solve(mid+1,r,L+l1,R);
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
int v=read();
tot++;
q[tot]=que(i,j,0,0,v,0);
}
}
for(int i=1;i<=m;i++){
int x1=read(),y1=read(),x2=read(),y2=read(),v=read();
tot++;
q[tot]=que(x1,y1,x2,y2,v,i);
}
solve(0,inf,1,tot);
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}