【分块】【链表】bzoj2738 矩阵乘法

http://www.cnblogs.com/jianglangcaijin/p/3460012.html

首先将矩阵的数字排序。设置size,每次将size个数字插入。插入时,我们用h[i][j]记录该位置的数字是否已经插入;用sum[i][j]表示子矩阵(1,1)到(i,j)已经插入的数字个数总和。每次插入后,暴力扫一次询问,若查询子矩阵的数字个数大于等于K则答案就在此次插入的数字中;然后将该询问从链表中删除。

怎样知道是插入的哪个数字呢?暴力O(sqrt(n))地扫描当前这段区间,依次判断这个数插入时是否恰好达到k个。

复杂度真心不知道怎么分析了……跪了……

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<list>
 5 using namespace std;
 6 struct Ask{int x1,y1,x2,y2,k,p;
 7 Ask(const int &x){scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k); p=x;}Ask(){}};
 8 list<Ask>Q;
 9 typedef list<Ask>::iterator ITER;
10 struct Val3{int v,x,y;}Ins[250001];
11 bool operator < (const Val3 &a,const Val3 &b){return a.v<b.v;}
12 int n,m,sumv[501][501],q,anss[60001];
13 bool vis[501][501];
14 void makeblock()
15 {
16     int sz=sqrt(q),sum=1; if(!sz) sz=1; 
17     for(;sum*sz<q;++sum)
18       {
19           int l=(sum-1)*sz+1; int r=sum*sz;
20           for(int i=l;i<=r;++i) vis[Ins[i].x][Ins[i].y]=1;
21           for(int i=1;i<=n;++i)
22             for(int j=1;j<=n;++j)
23               sumv[i][j]=sumv[i-1][j]+sumv[i][j-1]-sumv[i-1][j-1]+vis[i][j];
24           ITER it=Q.begin();
25           while(it!=Q.end())
26             {
27                 int hav=sumv[(*it).x2][(*it).y2]-sumv[(*it).x1-1][(*it).y2]-
28                 sumv[(*it).x2][(*it).y1-1]+sumv[(*it).x1-1][(*it).y1-1];
29                 if(hav>=(*it).k)
30               {
31                 for(int i=r;i>=l;--i)
32                   if(Ins[i].x>=(*it).x1 && Ins[i].x<=(*it).x2 &&
33                      Ins[i].y>=(*it).y1 && Ins[i].y<=(*it).y2)
34                        {
35                            if(hav==(*it).k)
36                              {
37                                  anss[(*it).p]=Ins[i].v;
38                                  break;
39                              } --hav;
40                        }
41                 ITER t=it; ++it; Q.erase(t);
42               }
43             else ++it;
44             }
45       }
46     int l=(sum-1)*sz+1; int r=q;
47     for(int i=l;i<=r;++i) vis[Ins[i].x][Ins[i].y]=1;
48     for(int i=1;i<=n;++i)
49       for(int j=1;j<=n;++j)
50           sumv[i][j]=sumv[i-1][j]+sumv[i][j-1]-sumv[i-1][j-1]+vis[i][j];
51     ITER it=Q.begin();
52     while(it!=Q.end())
53       {
54           int hav=sumv[(*it).x2][(*it).y2]-sumv[(*it).x1-1][(*it).y2]-
55             sumv[(*it).x2][(*it).y1-1]+sumv[(*it).x1-1][(*it).y1-1];
56           if(hav>=(*it).k)
57           {
58             for(int i=r;i>=l;--i)
59               if(Ins[i].x>=(*it).x1 && Ins[i].x<=(*it).x2 &&
60                  Ins[i].y>=(*it).y1 && Ins[i].y<=(*it).y2)
61                    {
62                      if(hav==(*it).k)
63                        {
64                            anss[(*it).p]=Ins[i].v;
65                            break;
66                        } --hav;
67                   }
68             ITER t=it; ++it; Q.erase(t);
69           }
70         else ++it;
71       }
72 }
73 int main()
74 {
75     scanf("%d%d",&n,&m);
76     for(int i=1;i<=n;++i)
77       for(int j=1;j<=n;++j)
78         {
79             scanf("%d",&Ins[++q].v);
80             Ins[q].x=i; Ins[q].y=j;
81         }
82     sort(Ins+1,Ins+q+1);
83     for(int i=1;i<=m;++i) Q.push_back(Ask(i));
84     makeblock();
85     for(int i=1;i<=m;++i) printf("%d
",anss[i]);
86     return 0;
87 }
原文地址:https://www.cnblogs.com/autsky-jadek/p/4147429.html