hihocoder 1236(2015北京网络赛 J题) 分块bitset乱搞题

 题目大意:

每个人有五门课成绩,初始给定一部分学生的成绩,然后每次询问给出一个学生的成绩,希望知道在给定的一堆学生的成绩比这个学生每门都低或者相等的人数

因为强行要求在线查询,所以题目要求,每次当前给定的学生成绩都异或上一次的答案

 

先将学生按每一门成绩都排一次序

这里将学生分块成sqrt(n)的块数,然后在当前块中用bitset容器来记录含有学生的状态

这里可以记录状态的前缀和,因为比后面成绩好的,必然比前面的学生的成绩也好

查询的时候只要查到正好比他高的学生属于哪一块,这样只要访问sqrt(n)次了

最后将5次得到的答案进行与操作就可以了

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 50001
 4 #define pii pair<int,int>
 5 int n , m , q , block;
 6 bitset<N> bs[5][300]; //记录前缀或值和
 7 pii val[5][N];
 8 
 9 void read()
10 {
11     scanf("%d%d" , &n , &m);
12     for(int i=0 ; i<n ; i++){
13         for(int j=0 ; j<5 ; j++){
14             scanf("%d" , &val[j][i].first);
15             val[j][i].second = i;
16         }
17     }
18     for(int i=0 ; i<5 ; i++) sort(val[i] , val[i]+n);
19 
20     block = (int)sqrt(n+0.5);
21     int i , j , k , index;
22     for(i=0 ; i<5 ; i++){
23         for(j=0 , index=0 ; j<n ; j+=block , index++){
24             int last = min(j+block,n);
25             bs[i][index].reset();
26             for(k=j ; k<last ; k++){
27                 bs[i][index].set(val[i][k].second);
28             }
29             if(index) bs[i][index] |= bs[i][index-1];
30           //  cout<<i<<" "<<j<<" "<<bs[i][index].to_string()<<endl;
31         }
32     }
33 }
34 
35 int find_pos(int k , int x)
36 {
37     int l=0 , r=n-1 , ans=-1;
38     while(r>=l){
39         int m=(l+r)>>1;
40         if(val[k][m].first<=x) l=m+1 , ans=m;
41         else r=m-1;
42     }
43     return ans;
44 }
45 
46 bitset<N> getStatus(int k , int x)
47 {
48     int pos = find_pos(k , x);
49     bitset<N> ans;
50     if(pos<0) return ans.reset();
51     int len = (pos+1)/block;
52     int st = block*len;
53     if(len>=1) ans = bs[k][len-1];
54     else ans.reset();
55     for(int i=st ; i<=pos ; i++)
56         ans.set(val[k][i].second);
57     return ans;
58 }
59 
60 void query()
61 {
62     int x , last=0;
63     bitset<N> ans[5];
64     scanf("%d" , &q);
65     while(q--){
66         for(int i=0 ; i<5 ; i++) ans[i].reset();
67         for(int i=0 ; i<5 ; i++){
68             scanf("%d" , &x);
69             x ^= last;
70             ans[i] = getStatus(i , x);
71             if(i) ans[i] &= ans[i-1];
72           //  cout<<i<<" "<<x<<" "<<ans[i].to_string()<<endl;
73         }
74         last = ans[4].count();
75         printf("%d\n" , last);
76     }
77 }
78 
79 int main()
80 {
81   //  freopen("a.in" , "r" , stdin);
82     int T;
83     scanf("%d" , &T);
84     while(T--){
85         read();
86         query();
87     }
88     return 0;
89 }

 

转载于:https://www.cnblogs.com/CSU3901130321/p/4839059.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值