无修子矩阵第 k k k大
数据范围: n , m ≤ 500 n,m\leq 500 n,m≤500
整体二分+二维树状数组当然你也可以大数据结构
s o l v e ( l , r , L , R ) solve(l,r,L,R) solve(l,r,L,R),表示在 [ l , r ] [l,r] [l,r]范围中,与操作 [ L , R ] [L,R] [L,R]有关(不一定对应原来的操作)
如果原矩阵的数 ≤ m i d \leq mid ≤mid,就在二维树状数组对应位置+1,如果碰到询问操作,那么查询区间 [ q l , q r ] [ql,qr] [ql,qr]的值,相当于查询 [ l , m i d ] [l,mid] [l,mid]中树状数组的值,如果 ≤ k \leq k ≤k,则答案在 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]中,此时把 k k k减去对应的个数【参照权值线段树】,否则答案就在左边,分治处理即可
时间复杂度: O ( n 2 l o g 2 n 2 ) O(n^2 log^2n^2) O(n2log2n2)【大概吧】
#include
#include
#include
#define LL long long
using namespace std;int n,m,cnt;
inline LL read()
{
LL f=0,d=1;char c;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
struct node{int x1,y1,x2,y2,k,id;}q[320011],q1[320010],q2[320011];
int ans[60010],c[501][501];
inline void add(int x,int y,int d)
{
for(register int i=x;i<=n;i+=i&-i)
for(register int j=y;j<=n;j+=j&-j)
c[i][j]+=d;
return;
}
inline int ask(int x,int y)
{
if(!x||!y) return 0;
int ans=0;
for(register int i=x;i;i-=i&-i)
for(register int j=y;j;j-=j&-j)
ans+=c[i][j];
return ans;
}
inline int sum(int x1,int y1,int x2,int y2){return ask(x2,y2)-ask(x2,y1-1)-ask(x1-1,y2)+ask(x1-1,y1-1);}
inline void solve(int l,int r,int L,int R)
{
if(L>R) return;
if(l==r)
{
for(register int i=L;i<=R;i++) if(q[i].id) ans[q[i].id]=l;
return;
}
int mid=l+r>>1,cnt1=0,cnt2=0;
for(register int i=L;i<=R;i++)
{
if(q[i].id==0)
{
if(q[i].k<=mid) add(q[i].x1,q[i].y1,1),q1[++cnt1]=q[i];
else q2[++cnt2]=q[i];
}
else
{
int x=sum(q[i].x1,q[i].y1,q[i].x2,q[i].y2);
if(x>=q[i].k) q1[++cnt1]=q[i];
else q[i].k-=x,q2[++cnt2]=q[i];
}
}
for(register int i=1;i<=cnt1;i++) if(q1[i].id==0) add(q1[i].x1,q1[i].y1,-1);
for(int i=L;i<=L+cnt1-1;i++) q[i]=q1[i-L+1];
for(int i=L+cnt1;i<=R;i++) q[i]=q2[i-L-cnt1+1];
solve(l,mid,L,L+cnt1-1);
solve(mid+1,r,L+cnt1,R);
return;
}
signed main()
{
n=read();m=read();
for(register int i=1;i<=n;i++)
for(register int j=1;j<=n;j++)
q[++cnt]=(node){i,j,0,0,read(),0};
for(register int i=1;i<=m;i++)
{
q[++cnt].x1=read();q[cnt].y1=read();q[cnt].x2=read();q[cnt].y2=read();q[cnt].k=read();
q[cnt].id=i;
}
solve(0,1e9,1,cnt);
for(register int i=1;i<=m;i++) printf("%d\n",ans[i]);
}