[BZOJ 2738]矩阵乘法
Posted Mafia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[BZOJ 2738]矩阵乘法相关的知识,希望对你有一定的参考价值。
[BZOJ 2738]矩阵乘法
题目
给你一个N*N的矩阵,不用算矩阵乘法,但是每次询问一个子矩形的第K小数。
INPUT
第一行两个数N,Q,表示矩阵大小和询问组数;
接下来N行N列一共N*N个数,表示这个矩阵;
再接下来Q行每行5个数描述一个询问:x1,y1,x2,y2,k表示找到以(x1,y1)为左上角、以(x2,y2)为右下角的子矩形中的第K小数。OUTPUT
对于每组询问输出第K小的数。
SAMPLE
INPUT
2 2
2 1
3 4
1 2 1 2 1
1 1 2 2 3OUTPUT
1
3
解题报告
一开始打了树状数组套主席树,然后$MLE+RE$不断= =
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 inline int read(){ 7 int sum(0); 8 char ch(getchar()); 9 for(;ch<\'0\'||ch>\'9\';ch=getchar()); 10 for(;ch>=\'0\'&&ch<=\'9\';sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 int n,q; 14 int a[505][505],num[250005]; 15 int size,cnt; 16 inline int lowbit(int x){ 17 return x&-x; 18 } 19 int rt[250005],lch[30000005],rch[30000005],sum[30000005]; 20 inline void update(int &x,int las,int pos,int w,int l,int r){ 21 x=++cnt; 22 lch[x]=lch[las]; 23 rch[x]=rch[las]; 24 sum[x]=sum[las]+w; 25 if(l==r) 26 return; 27 int mid((l+r)>>1); 28 if(pos<=mid) 29 update(lch[x],lch[las],pos,w,l,mid); 30 else 31 update(rch[x],rch[las],pos,w,mid+1,r); 32 } 33 int l,r,L[30],R[30]; 34 inline int query(int l,int r,int k){ 35 if(l==r) 36 return l; 37 int mid((l+r)>>1),suml(0),sumr(0); 38 for(int i=1;i<=l;++i) 39 suml+=sum[lch[L[i]]]; 40 for(int i=1;i<=r;++i) 41 sumr+=sum[lch[R[i]]]; 42 if(k<=sumr-suml){ 43 for(int i=1;i<=l;++i) 44 L[i]=lch[L[i]]; 45 for(int i=1;i<=r;++i) 46 R[i]=lch[R[i]]; 47 return query(l,mid,k); 48 } 49 else{ 50 for(int i=1;i<=l;++i) 51 L[i]=rch[L[i]]; 52 for(int i=1;i<=r;++i) 53 R[i]=rch[R[i]]; 54 return query(mid+1,r,k-(sumr-suml)); 55 } 56 } 57 int main(){ 58 n=read(),q=read(); 59 for(int i=1;i<=n;++i) 60 for(int j=1;j<=n;++j) 61 a[i][j]=read(),num[(i-1)*n+j]=a[i][j]; 62 sort(num+1,num+n*n+1); 63 size=unique(num+1,num+n*n+1)-num-1; 64 int edge(n*n); 65 for(int i=1;i<=n;++i) 66 for(int j=1;j<=n;++j){ 67 a[i][j]=lower_bound(num+1,num+size+1,a[i][j])-num; 68 for(int k=(i-1)*n+j;k<=edge;k+=lowbit(k)) 69 update(rt[k],rt[k],a[i][j],1,1,size); 70 } 71 while(q--){ 72 int aa(read()),b(read()),c(read()),d(read()),k(read()); 73 for(int i=aa;i<=c;++i){ 74 for(int j=1;j<b;++j) 75 for(int k=j;k<=edge;k+=lowbit(k)) 76 update(rt[k],rt[k],a[i][j],-1,1,size); 77 for(int j=d+1;j<=n;++j) 78 for(int k=j;j<=edge;k+=lowbit(k)) 79 update(rt[k],rt[k],a[i][j],-1,1,size); 80 } 81 l=r=0; 82 int tp1((aa-1)*n+b-1),tp2((c-1)*n+d); 83 for(int i=tp1;i>0;i-=lowbit(i)) 84 L[++l]=rt[i]; 85 for(int i=tp2;i>0;i-=lowbit(i)) 86 R[++r]=rt[i]; 87 printf("%d\\n",num[query(1,size,k)]); 88 for(int i=aa;i<=c;++i){ 89 for(int j=1;j<b;++j) 90 for(int k=j;k<=edge;k+=lowbit(k)) 91 update(rt[k],rt[k],a[i][j],1,1,size); 92 for(int j=d+1;j<=n;++j) 93 for(int k=j;j<=edge;k+=lowbit(k)) 94 update(rt[k],rt[k],a[i][j],1,1,size); 95 } 96 } 97 }
正解:
我们把所有点按权值从小到大排序,一次插入$n$个点,用前缀和维护一下
然后,用链表维护询问,每到一个询问,查看一下当前询问矩阵有多少个数,假如大于$k$,说明答案已经加入矩阵,倒序查询即可
1 #include<algorithm> 2 #include<iostream> 3 #include<cstring> 4 #include<cstdio> 5 using namespace std; 6 inline int read(){ 7 int sum(0); 8 char ch(getchar()); 9 for(;ch<\'0\'||ch>\'9\';ch=getchar()); 10 for(;ch>=\'0\'&&ch<=\'9\';sum=sum*10+(ch^48),ch=getchar()); 11 return sum; 12 } 13 struct data{ 14 int x,y,num; 15 inline bool operator<(const data &gg)const{ 16 return num<gg.num; 17 } 18 }nod[250005]; 19 int cnt; 20 struct query{ 21 int a,b,c,d,k; 22 }que[60005]; 23 int ans[60005]; 24 int n,q; 25 int map[505][505]; 26 int pre[60005],nxt[60005]; 27 int c[505][505],sum[505][505]; 28 inline bool check(data x,int a,int b,int c,int d){ 29 return x.x>=a&&x.x<=c&&x.y>=b&&x.y<=d; 30 } 31 inline void del(int x){ 32 pre[nxt[x]]=pre[x]; 33 nxt[pre[x]]=nxt[x]; 34 } 35 int main(){ 36 n=read(),q=read(); 37 // cout<<n<<" "<<q<<endl; 38 for(int i=1;i<=n;++i) 39 for(int j=1;j<=n;++j){ 40 map[i][j]=read(); 41 nod[++cnt].x=i; 42 nod[cnt].y=j; 43 nod[cnt].num=map[i][j]; 44 } 45 // cout<<cnt<<endl; 46 sort(nod+1,nod+cnt+1); 47 for(int i=1;i<=q;++i){ 48 que[i].a=read(),que[i].b=read(),que[i].c=read(),que[i].d=read(),que[i].k=read(); 49 pre[i]=i-1,nxt[i]=i+1; 50 } 51 nxt[0]=1; 52 for(int i=1;i<=n;++i){ 53 int sta((i-1)*n+1),en(i*n); 54 // cout<<"???"<<sta<<\' \'<<en<<endl; 55 for(int j=sta;j<=en;++j) 56 c[nod[j].x][nod[j].y]=1; 57 // cout<<"check the whole count array"<<endl; 58 // for(int j=1;j<=n;++j,cout<<endl) 59 // for(int k=1;k<=n;++k) 60 // cout<<c[j][k]<<\' \'; 61 for(int j=1;j<=n;++j) 62 for(int k=1;k<=n;++k) 63 sum[j][k]=sum[j-1][k]+sum[j][k-1]-sum[j-1][k-1]+c[j][k]; 64 // cout<<"check the whole sum array"<<endl; 65 // for(int j=1;j<=n;++j,cout<<endl) 66 // for(int k=1;k<=n;++k) 67 // cout<<sum[j][k]<<\' \'; 68 for(int j=nxt[0];j<=q;j=nxt[j]){ 69 // cout<<j<<endl; 70 int a(que[j].a),b(que[j].b),c(que[j].c),d(que[j].d),k(que[j].k); 71 int s(sum[c][d]-sum[a-1][d]-sum[c][b-1]+sum[a-1][b-1]); 72 // cout<<j<<\' \'<<s<<\' \'<<k<<\' \'<<que[j].k<<endl; 73 if(s<k) 74 continue; 75 // cout<<"not break?"<<s<<\' \'<<k<<endl; 76 for(int l=en;l>=sta;--l){ 77 if(check(nod[l],a,b,c,d)){ 78 // cout<<"init?"<<s<<\' \'<<k<<endl; 79 if(s==k){ 80 ans[j]=nod[l].num; 81 // cout<<"fuzhi?? "<<l<<\' \'<<nod[l].num<<endl; 82 del(j); 83 break; 84 } 85 else 86 --s; 87 } 88 } 89 } 90 } 91 for(int i=1;i<=q;++i) 92 printf("%d\\n",ans[i]); 93 }
暴力主席树不可取= =
以上是关于[BZOJ 2738]矩阵乘法的主要内容,如果未能解决你的问题,请参考以下文章