[BZOJ2738]矩阵乘法-[整体二分+树状数组]
Description
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
(N<=500,Q<=60000)
Solution
考虑二分答案,问题转化为求矩阵内为1的点数,可以用二维树状数组。
Code
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> using namespace std; struct P{int num,x,y;}a[250010];int cnt_a=0; bool cmp(P x,P y){return x.num<y.num;} int rk[100100],all=0; int n,m; struct node{int x,y,xx,yy,k,id; }q[60010],st[2][60010];int ans[60010]; int tree[510][510]; void add(int x,int y,int data){for(;x<=n;x+=x&-x)for(int j=y;j<=n;j+=j&-j) tree[x][j]+=data;} int query(int x,int y){int re=0;for(;x;x-=x&-x)for(int j=y;j;j-=j&-j) re+=tree[x][j];return re;} int now; void solve(int ql,int qr,int ansl,int ansr) { if (ql>qr) return; if (ansl==ansr) { for (int i=ql;i<=qr;i++) ans[q[i].id]=ansl; return; } int ansmid=ansl+ansr>>1,cnt,js0=0,js1=0; for (;now<ansmid;) now++,add(a[now].x,a[now].y,1); for(;now>ansmid;now--) add(a[now].x,a[now].y,-1); for (int i=ql;i<=qr;i++) { cnt=query(q[i].xx,q[i].yy)+query(q[i].x-1,q[i].y-1)-query(q[i].x-1,q[i].yy)-query(q[i].xx,q[i].y-1); if (cnt>=q[i].k) st[0][++js0]=q[i]; else st[1][++js1]=q[i]; } for (int i=1;i<=js0;i++) q[i+ql-1]=st[0][i]; for (int i=1;i<=js1;i++) q[i+ql+js0-1]=st[1][i]; solve(ql,ql+js0-1,ansl,ansmid); solve(ql+js0,qr,ansmid+1,ansr); } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) for (int j=1;j<=n;j++) { scanf("%d",&a[++cnt_a].num);a[cnt_a].x=i;a[cnt_a].y=j; } sort(a+1,a+cnt_a+1,cmp); for (int i=1;i<=m;i++) { scanf("%d%d%d%d%d",&q[i].x,&q[i].y,&q[i].xx,&q[i].yy,&q[i].k);q[i].id=i; } solve(1,m,0,n*n); for (int i=1;i<=m;i++) printf("%d\n",a[ans[i]].num); }