链接:http://hihocoder.com/problemset/problem/1236
思路;
有n个五维的向量,给出q个询问,每个询问是一个五维向量,问有多少个向量没有一维比这个向量大。并且答案需要加密,除了第一个答案,其他答案都要和上一个答案异或。
因为是强制在线所以不能用cdq分治写。。我们可以用stl里面的bitset来写这道题,但是因为数据还是太大了,这里我们可以用分块处理下,降低空间复杂度,需要用的时候直
接二分查找需要的块,预处理后可以o(1)获取前k-1个块的信息,然后我们对当前块逐个更新下就好了。
这里 bit[i][j]代表第i维前j个块有多少个人。
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 5e4+10; struct node{ int val,id; node(){}; node(int val,int id):val(val),id(id){} bool operator < (const node &b) const{ if(val == b.val) return id < b.id; return val < b.val; } }a[6][M]; bitset<M>bit[6][300]; bitset<M>ans; bitset<M>temp; int block; int num; int main() { int t,n,m,q; scanf("%d",&t); while(t--){ scanf("%d%d",&n,&m); for(int i = 1;i <= n;i ++) for(int j = 1;j <= 5;j ++) scanf("%d",&a[j][i].val),a[j][i].id = i; for(int i = 1;i <= 5;i ++) sort(a[i]+1,a[i]+n+1); block = sqrt(n); //分块,预处理 for(int i = 1;i <= 5;i ++){ for(int j = 1;(j-1)*block < n;j ++){ bit[i][j].reset(); bit[i][j] = bit[i][j-1]; int st = (j-1)*block; for(int k = 1;k <= block&&st+k<=n;k ++){ bit[i][j].set(a[i][st+k].id); } } } int q; scanf("%d",&q); int now[6]; int pre = 0; while(q--){ for(int i = 1;i <= 5;i ++){ scanf("%d",&now[i]); now[i]^=pre; } ans.reset(); for(int i = 1;i <= 5;i ++){ int tmp = lower_bound(a[i]+1,a[i]+n+1,node(now[i],n+1))-a[i]-1; tmp = tmp/block; temp = bit[i][tmp];//获取之前块的信息 for(int j = tmp*block+1;a[i][j].val<=now[i]&&j<=n;j++){ //当前块这个更新 temp.set(a[i][j].id); } if(i == 1) ans = temp; else ans &= temp; } int num = ans.count(); pre = num; printf("%d ",num); } } return 0; }