题目大意:给定一个矩阵,多次求一个子矩阵中的第k小
正解:CDQ分治 不会
二维莫队? 不会
于是果断分块大法好(又是
我们将这n*n个数排序 分n次插入 每次插入n个
每次插入后 去链表上处理尚未出解的询问(我懒得写链表写了并查集) 如果当前询问的子矩阵内已经插入大于等于k个数 那么答案一定在当次插入的n个数中 暴力查找即可
时间复杂度O(n^3+nq) 好卡……
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define M 510 using namespace std; struct abcd{ int x,y,num; bool operator < (const abcd &Y) const { return num < Y.num ; } }a[M*M]; struct query{ int x1,y1,x2,y2,k; }q[60600]; int n,m; int map[M][M],cnt[M][M],sum[M][M],ans[60600]; int fa[60600]; int Find(int x) { if(!fa[x]||fa[x]==x) return fa[x]=x; return fa[x]=Find(fa[x]); } int main() { int i,j,k; cin>>n>>m; for(i=1;i<=n;i++) for(j=1;j<=n;j++) { scanf("%d",&map[i][j]); a[i*n-n+j].x=i; a[i*n-n+j].y=j; a[i*n-n+j].num=map[i][j]; } for(i=1;i<=m;i++) scanf("%d%d%d%d%d",&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2,&q[i].k); sort(a+1,a+n*n+1); for(i=1;i<=n;i++) { for(j=1;j<=n;j++) { abcd &temp=a[i*n-n+j]; cnt[temp.x][temp.y]=1; } for(j=1;j<=n;j++) for(k=1;k<=n;k++) sum[j][k]=cnt[j][k]+sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]; for(k=Find(1);k<=m;k=Find(k+1)) { int x1=q[k].x1-1; int y1=q[k].y1-1; int x2=q[k].x2; int y2=q[k].y2; int temp=sum[x2][y2]+sum[x1][y1]-sum[x1][y2]-sum[x2][y1]; if(temp<q[k].k) continue; temp-=q[k].k; for(j=n;j;j--) if(a[i*n-n+j].x>x1&&a[i*n-n+j].y>y1&&a[i*n-n+j].x<=x2&&a[i*n-n+j].y<=y2) if(!temp--) { ans[k]=a[i*n-n+j].num; break; } fa[k]=k+1; } } for(i=1;i<=m;i++) printf("%d\n",ans[i]); }