2016_1_17
给5w个5维坐标,5w次询问:给出一个点,求5维都不大于这个点的点数量,强制在线
第一行两个数字n,m,分别代表初始点和询问。
接下去n行,每行5个数代表坐标(坐标小于5w)
接下去m行,每行5个数,真正的询问坐标为当前给的数字异或上一次的答案(第一次就不用异或了)。
每行一个数字对应询问
2 2
1 1 1 1 1
2 2 2 2 2
1 1 1 1 1
3 3 3 3 3
1
2
20%数据 n<=100
100%数据 n<=5w
之前没有看bitsat ,这道题血崩只有二十分。做法是按每一维排序,然后预处理出每一维每块内有哪些点,就用bitsat来处理了,取个前缀。然后关于每一个询问,每一维查询有哪些是合法的,然后每一维取and,最后count就是答案了。
1 #include <cstdio> 2 #include <cstdlib> 3 #include <iostream> 4 #include <algorithm> 5 #include <cstring> 6 #include <cmath> 7 #include <bitset> 8 using namespace std; 9 const int N = 60003; 10 const int INF = 0x7fffffff; 11 bitset<N>kuai[5][243]; 12 bitset<N>ans,linshi; 13 int n,m; 14 struct hp { 15 int x,key; 16 bool operator < (const hp& p) const { 17 return x<p.x; 18 } 19 }a[5][N]; 20 int b[5],last,size; 21 int main() { 22 scanf("%d%d",&n,&m); 23 for(int i = 1 ; i <= n ; ++i) 24 for(int j = 0 ; j < 5 ; ++j) 25 scanf("%d",&a[j][i].x),a[j][i].key = i; 26 for(int j = 0 ; j < 5 ; ++j) sort(a[j]+1,a[j]+1+n); 27 size = sqrt(n); 28 for(int j = 0 ; j < 5 ; ++j) { 29 last = 1; 30 for(int i = 1 ; i <= n ; ++i) { 31 int k = i/size; 32 if(i%size!=0) k++; 33 if(last!=k) kuai[j][k] = kuai[j][k-1],last = k; 34 kuai[j][k].set(a[j][i].key); 35 } 36 } 37 last = 0; 38 for(int i = 1 ; i <= m ; ++i) { 39 for(int j = 0 ; j < 5 ; ++j) scanf("%d",&b[j]),b[j]^=last; 40 for(int j = 0 ; j < 5 ; ++j) { 41 int x = b[j]; 42 int l = 1,r = n,maxn = 0; 43 do { 44 int mid = (l+r)>>1; 45 if(a[j][mid].x <= x) l = mid + 1,maxn = max(maxn,mid); 46 else r = mid; 47 }while(l<r); 48 if(a[j][r].x <= x) maxn = max(maxn,r); 49 if(a[j][l].x <= x) maxn = max(maxn,l); 50 while(a[j][maxn+1].x <= x && maxn < n) maxn++; 51 maxn = min(maxn,n); 52 if(maxn==0) { 53 ans.reset(); 54 break; 55 } 56 int RP = maxn/size; 57 if(j==0) ans = kuai[j][RP]; 58 else linshi = kuai[j][RP]; 59 for(int kk = maxn/size*size+1 ; kk <= maxn ; ++kk) { 60 if(j==0) ans.set(a[j][kk].key); 61 else linshi.set(a[j][kk].key); 62 } 63 if(j!=0)ans &= linshi; 64 } 65 last = ans.count(); 66 printf("%d\n",last); 67 } 68 }