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 }
View Code

 

转载于:https://www.cnblogs.com/Blue233333/p/8240993.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值