整体二分&&bzoj 2738学习笔记

 
 


整体二分大概就是这么个东西:

二分答案,对当前二份出来的答案有影响的元素扔进集合中,然后拿出当前当前答案有贡献的询问来更新

感觉还是抽象了一点,那么来说道题吧


给你一个N*N的矩阵,每次询问一个子矩形的第K小数。


首先离线所有询问,将矩阵按大小排序

二分答案,将小于答案的数扔到树状数组里面,询问当前询问矩阵中有多少合法的数

如果多了把当前询问下沉,否则上浮

所谓下沉和上浮就是指交换询问顺序使得递归下去询问可以进行下去


时间复杂度是q*log^2*logN


//Copyright(c)2016 liuchenrui
#include<bits/stdc++.h>
using namespace std;
inline void splay(int &v){
	v=0;char c=0;int p=1;
	while(c<'0' || c>'9'){if(c=='-')p=-1;c=getchar();}
	while(c>='0' && c<='9'){v=(v<<3)+(v<<1)+c-'0';c=getchar();}
	v*=p;
}
#define lowbit(i) (i&(-i))
int v[505][505];
int n,q_cnt;int cnt=0,mx=0;
void insert(int x,int y,int z){
	for(int i=x;i<=n;i+=lowbit(i)){
		for(int j=y;j<=n;j+=lowbit(j)){
			v[i][j]+=z;
		}
	}
}
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+=v[i][j];
		}
	}
	return ans;
}
struct data{
	int x,y,v;
	bool operator < (const data &a)const{
		return v<a.v;
	}
}a[250010];
struct Q{
	int x1,y1,x2,y2,k;
}q[60010];int ans[60010];
int T;
bool is[60010];
int tmp[60010],id[60010];
int query(int id){
	return query(q[id].x2,q[id].y2)-query(q[id].x1-1,q[id].y2)
	-query(q[id].x2,q[id].y1-1)+query(q[id].x1-1,q[id].y1-1);
}
void calc(int l,int r,int L,int R){
	if(l>r)return;if(L==R)return;int mid=L+R>>1;
	while(a[T+1].v<=mid&&T<cnt)T++,insert(a[T].x,a[T].y,1);
	while(a[T].v>mid)insert(a[T].x,a[T].y,-1),T--;
	int tot=0;
	for(int i=l;i<=r;i++){
		if(query(id[i])>=q[id[i]].k){
			tot++;is[i]=1;ans[id[i]]=mid;
		}
		else is[i]=0;
	}
	int l1=l,l2=l+tot;
	for(int i=l;i<=r;i++){
		if(is[i])tmp[l1++]=id[i];
		else tmp[l2++]=id[i];
	}
	for(int i=l;i<=r;i++)id[i]=tmp[i];
	calc(l,l1-1,L,mid),calc(l1,l2-1,mid+1,R);
}
int main(){
	freopen("xxx.in","r",stdin);
	freopen("xxx.out","w",stdout);
	splay(n);splay(q_cnt);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			int x;splay(x);
			a[++cnt].v=x;a[cnt].x=i;a[cnt].y=j;
			mx=max(mx,x);
		}
	}
	sort(a+1,a+cnt+1);
	for(int i=1;i<=q_cnt;i++){
		splay(q[i].x1),splay(q[i].y1);
		splay(q[i].x2),splay(q[i].y2);
		splay(q[i].k);id[i]=i;
	}
	calc(1,q_cnt,0,mx+1);
	for(int i=1;i<=q_cnt;i++){
		printf("%d\n",ans[i]);
	}
}



你可能感兴趣的:(整体二分)