• 周日. 7月 3rd, 2022

5G编程聚合网

5G时代下一个聚合的编程学习网

热门标签

[BZOJ 2738]矩阵乘法

admin

11月 28, 2021

[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
",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
",ans[i]);
93 }

AC Code

暴力主席树不可取= =

发表评论

您的电子邮箱地址不会被公开。