【CDQ-整体二分】BZOJ 2738 矩阵乘法
题意:给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数
思路:
整体二分+二维树状数组
二分询问的答案mid,将数值小等mid的全部插入二维树状数组
然后查询每个矩阵内的元素个数,若数量>K-1则放左边,否则放右边
继续向下分治,左边二分l-mid,右边mid-r
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<ctime> #include<vector> #include<queue> #include<algorithm> #include<map> #include<cmath> #define inf 1000000000 #define mod 1000000007 #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } int n,m,cnt,T; int t[505][505],ans[60005]; int id[60005],tmp[60005]; bool mark[60005]; struct que{ int x1,x2,y1,y2,K; }q[60005]; struct data{ int x,y,val; }a[250005]; bool operator<(data a,data b) { return a.val<b.val; } void add(int x,int y,int val) { for(int i=x;i<=n;i+=i&-i) for(int j=y;j<=n;j+=j&-j) t[i][j]+=val; } int query(int x,int y) { int tmp=0; for(int i=x;i;i-=i&-i) for(int j=y;j;j-=j&-j) tmp+=t[i][j]; return tmp; } int query(int k) { int x1=q[k].x1,y1=q[k].y1,x2=q[k].x2,y2=q[k].y2; return query(x2,y2)+query(x1-1,y1-1)-query(x1-1,y2)-query(x2,y1-1); } void solve(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].val<=mid&&T<cnt){add(a[T+1].x,a[T+1].y,1);T++;} while(a[T].val>mid){add(a[T].x,a[T].y,-1);T--;} int cnt=0; for(int i=l;i<=r;i++) { if(query(id[i])>q[id[i]].K-1) { mark[i]=1;ans[id[i]]=mid;cnt++; } else mark[i]=0; } int l1=l,l2=l+cnt; for(int i=l;i<=r;i++) if(mark[i])tmp[l1++]=id[i]; else tmp[l2++]=id[i]; for(int i=l;i<=r;i++)id[i]=tmp[i]; solve(l,l1-1,L,mid);solve(l1,l2-1,mid+1,R); } int main() { n=read();m=read(); int mx=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { a[++cnt].x=i,a[cnt].y=j,a[cnt].val=read(); mx=max(a[cnt].val,mx); } sort(a+1,a+cnt+1); for(int i=1;i<=m;i++) { q[i].x1=read(),q[i].y1=read(),q[i].x2=read(),q[i].y2=read(),q[i].K=read(); } for(int i=1;i<=m;i++)id[i]=i; solve(1,m,0,mx+1); for(int i=1;i<=m;i++) printf("%d\n",ans[i]); return 0; }