题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2738
题意:给出一个矩阵。每次询问子矩阵第K小值。
思路:首先将矩阵的数字排序。设置size,每次将size个数字插入。插入时,我们用h[i][j]记录该位置的数字是否已经插入;用sum[i][j]表示子矩阵(1,1)到(i,j)已经插入的数字个数总和。每次插入后,暴力扫一次询问,若查询子矩阵的数字个数大于等于K则答案就在此次插入的数字中;然后将该询问从链表中删除。
struct node
{
int k,x,y;
int operator<(const node &a) const
{
return k<a.k;
}
};
node a[N*N];
struct Node
{
int x1,y1,x2,y2,ans,K;
Node *next,*pre;
void get()
{
RD(x1,y1); RD(x2,y2); RD(K);
}
};
Node b[N*N];
int h[N][N],sum[N][N];
int n,m,size;
int get(Node *p)
{
int x1=p->x1,y1=p->y1;
int x2=p->x2,y2=p->y2;
return sum[x2][y2]-sum[x2][y1-1]-sum[x1-1][y2]+sum[x1-1][y1-1];
}
void deal()
{
size=2.5*n*n/sqrt(1.0*m)+1;
int i,j,k,L,R;
Node *p,*end=&b[m+1];
for(L=1;L<=n*n;L+=size)
{
R=min(n*n,L+size-1);
for(i=L;i<=R;i++) h[a[i].x][a[i].y]=1;
FOR1(i,n) FOR1(j,n)
{
sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+h[i][j];
}
for(p=b[0].next;p!=end;p=p->next)
{
k=get(p);
if(k<p->K) continue;
for(i=R;i>=L;i--)
{
if(a[i].x>=p->x1&&a[i].x<=p->x2&&a[i].y>=p->y1&&a[i].y<=p->y2)
{
if(k==p->K)
{
p->ans=a[i].k;
break;
}
k--;
}
}
p->pre->next=p->next;
p->next->pre=p->pre;
}
}
}
int main()
{
RD(n,m);
int i,j,k=0;
FOR1(i,n) FOR1(j,n)
{
RD(a[++k].k);
a[k].x=i;
a[k].y=j;
}
sort(a+1,a+k+1);
FOR1(i,m)
{
b[i].get();
b[i].next=&b[i+1];
b[i+1].pre=&b[i];
}
b[0].next=&b[1];
b[1].pre=&b[0];
deal();
FOR1(i,m) PR(b[i].ans);
}