BZOJ2738: 矩阵乘法
n<=500,n*n的矩阵,m<=60000个询问每次问子矩阵第K小。
方法一:第K小什么的是可以二分的,那就整体二分套二维树状数组吧!
这里有一个细节优化,本来整体二分是logMax的嘛,可以先把数字排个序,就变成logn了。这是没优化的后果(话说3个log确实极卡)
方法二:分块,n*n个数字从小到大排,然后分n次加入,每次加入n个算贡献,在询问里把这些数字的贡献减掉,如果某个询问的K<=0了,说明他的答案在这几个数里面,暴力查一下即可。n^3+nq也极卡。。
1 #include<string.h> 2 #include<stdlib.h> 3 #include<stdio.h> 4 //#include<assert.h> 5 #include<algorithm> 6 //#include<iostream> 7 using namespace std; 8 9 int n,m; 10 #define maxn 350011 11 struct Ope 12 { 13 int x,y,z,w,u,id,type; 14 //type=1: xiugai dian x,y wei z 15 //type=0: chaxun (x,y) dao (z,w) di u da bianhao id 16 }q[maxn],al[maxn],ar[maxn]; int len=0; 17 int ans[maxn]; 18 19 struct BIT 20 { 21 int a[511][511]; 22 void add(int x,int y,int v) 23 { 24 for (;x<=n;x+=x&-x) 25 for (int i=y;i<=n;i+=i&-i) 26 a[x][i]+=v; 27 } 28 int query(int x,int y) 29 { 30 int ans=0; 31 for (;x;x-=x&-x) 32 for (int i=y;i;i-=i&-i) 33 ans+=a[x][i]; 34 return ans; 35 } 36 }t; 37 38 void solve(int L,int R,int ql,int qr) 39 { 40 if (L>R || ql>qr) return; 41 if (L==R) 42 { 43 for (int i=ql;i<=qr;i++) if (q[i].type==0) ans[q[i].id]=L; 44 return; 45 } 46 int mid=(L+R)>>1,lal=0,lar=0; 47 for (int i=ql;i<=qr;i++) 48 { 49 if (q[i].type) 50 { 51 if (q[i].z<=mid) t.add(q[i].x,q[i].y,1),al[++lal]=q[i]; 52 else ar[++lar]=q[i]; 53 } 54 else 55 { 56 int tmp=t.query(q[i].z,q[i].w)-t.query(q[i].z,q[i].y-1) 57 -t.query(q[i].x-1,q[i].w)+t.query(q[i].x-1,q[i].y-1); 58 if (tmp>=q[i].u) al[++lal]=q[i]; 59 else q[i].u-=tmp,ar[++lar]=q[i]; 60 } 61 } 62 for (int i=1;i<=lal;i++) if (al[i].type) t.add(al[i].x,al[i].y,-1); 63 for (int i=1,j=ql;i<=lal;i++,j++) q[j]=al[i]; 64 for (int i=1,j=ql+lal;i<=lar;i++,j++) q[j]=ar[i]; 65 solve(L,mid,ql,ql+lal-1); 66 solve(mid+1,R,ql+lal,qr); 67 } 68 69 int main() 70 { 71 scanf("%d%d",&n,&m); 72 for (int i=1;i<=n;i++) 73 for (int j=1;j<=n;j++) 74 { 75 len++; scanf("%d",&q[len].z); 76 q[len].x=i; q[len].y=j; q[len].type=1; 77 } 78 for (int i=1;i<=m;i++) len++,scanf("%d%d%d%d%d",&q[len].x,&q[len].y,&q[len].z,&q[len].w,&q[len].u), 79 q[len].id=i,q[len].type=0; 80 solve(0,0x3f3f3f3f,1,len); 81 for (int i=1;i<=m;i++) printf("%d\n",ans[i]); 82 return 0; 83 }