hihocoder1236(北京网络赛J):scores 分块+bitset

北京网络赛的题- -。当时没思路,听大神们说是分块+bitset,想了一下发现确实可做,就试了一下,T了好多次终于过了

题意:

初始有n个人,每个人有五种能力值,现在有q个查询,每次查询给五个数代表查询的五种能力值,输出有多少个人每种能力值都比查询的小

n和q都是50000,每种能力值最大也为50000

思路:

对于某一个大小的能力值,有哪些人的此项能力值比他小可以用一个50000的bitset表示。这样我们在查询的时候就可以拿到5个对应的bitset,对其进行and就可以得出最终的人数

这样每组询问的复杂度为5*n/32 总复杂度较高但勉强可以接受。

但是这样做有一点问题就是要开5*50000个大小为50000的bitset,显然这样会超内存。。于是想到将bitset分块,这样虽然询问时需要花费一定时间(sqrt)来找到5个bitset

但是显然这个时间是小于n/32的,所以并不会对总时间造成较大的影响,于是显然可行

注意一点就是分块的时候不仅要按照分数段分块,还要按照人数分块,否则如果某个分数段人数太多就gg了

代码:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 bitset<50010>b[7][500];
 4 bitset<50010>tmp;
 5 int n,m,q;
 6 int a[50010][7];
 7 vector<int>v[7][50010];
 8 bitset<50010>p[7];
 9 int tt=10;
10 int now[5];
11 vector<int>d[7];
12 int main()
13 {
14     //freopen("in.txt","r",stdin);
15     int T;
16     scanf("%d",&T);
17     while(T--)
18     {
19         scanf("%d%d",&n,&m);
20         for(int i=0; i<5; i++)
21         {
22             d[i].clear();
23             for(int j=1; j<=m; j++)
24             {
25                 v[i][j].clear();
26             }
27         }
28         for(int i=0;i<5;i++)
29         {
30             for(int j=1;j<=300;j++)
31             {
32                 b[i][j].reset();
33             }
34         }
35         for(int i=0; i<n; i++)
36         {
37             for(int j=0; j<5; j++)
38             {
39                 scanf("%d",a[i]+j);
40                 v[j][a[i][j]].push_back(i);
41             }
42         }
43         int tm=0;
44         for(int i=0; i<5; i++)
45         {
46             tm=0;
47             tmp.reset();
48             b[i][0]=tmp;
49             d[i].push_back(0);
50             for(int j=0; j<=m; j++)
51             {
52                 for(int to:v[i][j])
53                 {
54                     tmp[to]=1;
55                     tm++;
56                 }
57                 if(tm>sqrt(n)||j-d[i][(int)d[i].size()-1]>sqrt(m)||j==m)
58                 {
59                     b[i][(int)d[i].size()]=tmp;
60                     d[i].push_back(j);
61                     tm=0;
62                 }
63             }
64         }
65         scanf("%d",&q);
66         int pre=0;
67         tm=0;
68         while(q--)
69         {
70             for(int i=0; i<5; i++)
71             {
72                 scanf("%d",now+i);
73                 now[i]^=pre;
74             }
75             for(int i=0; i<5; i++)
76             {
77                 int kk=upper_bound(d[i].begin(),d[i].end(),now[i])-d[i].begin();
78                 kk--;
79                 p[i]=b[i][kk];
80                 for(int j=d[i][kk]+1; j<=now[i]; j++)
81                 {
82                     for(int to:v[i][j])
83                     {
84                         p[i][to]=1;
85                     }
86                 }
87                 //p&=tmp;
88             }
89             for(int i=1;i<5;i++)
90             {
91                 p[0]&=p[i];
92             }
93             int ans=p[0].count();
94             pre=ans;
95             printf("%d\n",ans);
96         }
97     }
98     return 0;
99 }
View Code

 

posted @ 2015-09-23 11:34  PlasticSpirit  阅读(481)  评论(0编辑  收藏  举报