国家集训队 矩阵乘法
题解:
考虑到答案具有单调性,我们将其放入二维树状数组/二维线段树即可。
代码:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 505 #define Q 60050 #define ll long long inline int rd() { int f=1,c=0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=10*c+ch-'0';ch=getchar();} return f*c; } int n,m,ans[Q],mx,lp[N*N],rp[N*N],to[N*N]; struct node { int x,y,k; }p[N*N]; struct sqr { int x_,y_,_x,_y,k,id; void read() { x_ = rd(),y_ = rd(),_x = rd(),_y = rd(),k = rd(); } }q[Q],tmpl[Q],tmpr[Q]; bool cmp(node a,node b) { return a.k<b.k; } struct BIT { ll f[N][N]; void up(int x,int y,ll d) { if(!x||!y)return ; for(int i=x;i<N;i+=(i&-i)) for(int j=y;j<N;j+=(j&-j)) f[i][j]+=d; } ll down(int x,int y) { if(!x||!y)return 0; ll ret = 0; for(int i=x;i;i-=(i&-i)) for(int j=y;j;j-=(j&-j)) ret+=f[i][j]; return ret; } }tr; void update(int k,int d) { for(int i=lp[k];i<=rp[k];i++) tr.up(p[i].x,p[i].y,d); } ll ask(int x_,int y_,int _x,int _y) { return tr.down(_x,_y)+tr.down(x_-1,y_-1)-tr.down(_x,y_-1)-tr.down(x_-1,_y); } int tim; void divi(int l,int r,int beg,int ens) { if(beg>ens)return ; if(l==r) { for(int i=beg;i<=ens;i++) ans[q[i].id] = to[l]; return ; } int mid = (l+r)>>1; while(tim<mid)tim++,update(tim,1); while(tim>mid)update(tim,-1),tim--; int lt = 0,rt = 0; for(int i=beg;i<=ens;i++) { ll sum = ask(q[i].x_,q[i].y_,q[i]._x,q[i]._y); if(sum>=q[i].k)tmpl[++lt] = q[i]; else tmpr[++rt] = q[i]; } for(int i=beg;i<=beg+lt-1;i++)q[i]=tmpl[i-beg+1]; for(int i=beg+lt;i<=ens;i++)q[i]=tmpr[i-beg-lt+1]; divi(l,mid,beg,beg+lt-1); divi(mid+1,r,beg+lt,ens); } int main() { n = rd(),m = rd(); for(int i=1;i<=n*n;i++) { p[i].x = (i-1)/n+1; p[i].y = (i-1)%n+1; p[i].k = rd(); } sort(p+1,p+1+n*n,cmp); for(int las=-1,i=1;i<=n*n;i++) { if(p[i].k!=las) { rp[mx] = i-1; las = p[i].k; mx++; lp[mx] = i; to[mx] = las; } p[i].k = mx; } rp[mx] = n*n; for(int i=1;i<=m;i++) q[i].read(),q[i].id=i; divi(1,mx+1,1,m); for(int i=1;i<=m;i++) printf("%d ",ans[i]); return 0; }