1. 程式人生 > >[BZOJ 2738]矩陣乘法

[BZOJ 2738]矩陣乘法

mes nbsp pda splay 樹狀 getc ++ 矩陣乘法 array

[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 3

OUTPUT

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 }
MLE的主席樹

正解:

我們把所有點按權值從小到大排序,一次插入$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 }
AC Code

暴力主席樹不可取= =

[BZOJ 2738]矩陣乘法