luogu 1527

题目链接

解法

整体二分
首先有一个显然的对于每组询问都二分答案,然后 O ( n 2 ) O(n^2) 查询询问矩阵的做法。
在此基础上,本来笔者想要用主席树的在线算法解决问题,但是复杂度是 O ( q n l o g 2 n ) O(qnlog^2n) ,不能通过,随即考虑整体二分。
整体二分的思路是将所有操作放在一起处理,一次性把所有询问的答案处理出来。
考虑本题,将矩阵内的每个值当作一次赋值操作,然后用二维树状数组维护,每次询问的时候考虑当前答案下询问矩阵中的数是否已经大于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;
}

发布了95 篇原创文章 · 获赞 9 · 访问量 3178

猜你喜欢

转载自blog.csdn.net/wmhtxdy/article/details/104756878