题目大意:
每个人有五门课成绩,初始给定一部分学生的成绩,然后每次询问给出一个学生的成绩,希望知道在给定的一堆学生的成绩比这个学生每门都低或者相等的人数
因为强行要求在线查询,所以题目要求,每次当前给定的学生成绩都异或上一次的答案
先将学生按每一门成绩都排一次序
这里将学生分块成sqrt(n)的块数,然后在当前块中用bitset容器来记录含有学生的状态
这里可以记录状态的前缀和,因为比后面成绩好的,必然比前面的学生的成绩也好
查询的时候只要查到正好比他高的学生属于哪一块,这样只要访问sqrt(n)次了
最后将5次得到的答案进行与操作就可以了
#include<bits/stdc++.h>
using namespace std;
#define N 50001
#define pii pair<int,int>
int n , m , q , block;
bitset<N> bs[][]; //记录前缀或值和
pii val[][N]; void read()
{
scanf("%d%d" , &n , &m);
for(int i= ; i<n ; i++){
for(int j= ; j< ; j++){
scanf("%d" , &val[j][i].first);
val[j][i].second = i;
}
}
for(int i= ; i< ; i++) sort(val[i] , val[i]+n); block = (int)sqrt(n+0.5);
int i , j , k , index;
for(i= ; i< ; i++){
for(j= , index= ; j<n ; j+=block , index++){
int last = min(j+block,n);
bs[i][index].reset();
for(k=j ; k<last ; k++){
bs[i][index].set(val[i][k].second);
}
if(index) bs[i][index] |= bs[i][index-];
// cout<<i<<" "<<j<<" "<<bs[i][index].to_string()<<endl;
}
}
} int find_pos(int k , int x)
{
int l= , r=n- , ans=-;
while(r>=l){
int m=(l+r)>>;
if(val[k][m].first<=x) l=m+ , ans=m;
else r=m-;
}
return ans;
} bitset<N> getStatus(int k , int x)
{
int pos = find_pos(k , x);
bitset<N> ans;
if(pos<) return ans.reset();
int len = (pos+)/block;
int st = block*len;
if(len>=) ans = bs[k][len-];
else ans.reset();
for(int i=st ; i<=pos ; i++)
ans.set(val[k][i].second);
return ans;
} void query()
{
int x , last=;
bitset<N> ans[];
scanf("%d" , &q);
while(q--){
for(int i= ; i< ; i++) ans[i].reset();
for(int i= ; i< ; i++){
scanf("%d" , &x);
x ^= last;
ans[i] = getStatus(i , x);
if(i) ans[i] &= ans[i-];
// cout<<i<<" "<<x<<" "<<ans[i].to_string()<<endl;
}
last = ans[].count();
printf("%d\n" , last);
}
} int main()
{
// freopen("a.in" , "r" , stdin);
int T;
scanf("%d" , &T);
while(T--){
read();
query();
}
return ;
}