hihocoder1236(2015长春网赛J题) Scores(bitset && 分块)
题意:给你50000个五维点(a1,a2,a3,a4,a5),50000个询问(q1,q2,q3,q4,q5),问已知点里有多少个点(x1,x2,x3,x4,x5)满足(xi<=qi,i=1,2,3,4,5),强制在线。
一看题的一个直接思路是五维树状数组,算了一下复杂度还不如暴力判,遂不会做。赛后问了一下大神们,知道是分块+bitset,觉得处理挺巧妙的,就留一份题解在这里。
具体的做法是这样子的。定义一个bitset<maxn> bs[i][k],表示第i维前k块所对应的点的bitset,之所以要分块是因为不分块的话空间开不下。所以现在每一个询问过来,其实就是对每一维求出所有比它小的bitset,这些bitset & 起来的结果的count就是要求的答案。
我觉得这里比较玄妙的点是分块bitset,用分块去避开空间不够的影响在很多优化的问题上都是挺有帮助的。
#pragma warning(disable:4996) #include<algorithm> #include<stdio.h> #include<stdlib.h> #include<string.h> #include<math.h> #include<iostream> #include<queue> #include <list> #include<time.h> #include<bitset> using namespace std; #define maxn 50005 struct Node { int val, id; Node(int _val, int _id) :val(_val), id(_id){} Node(){} bool operator < (const Node &b)const{ if (val == b.val) return id < b.id; return val < b.val; } }a[6][maxn]; int n,m,q; bitset<maxn> bs[5][250]; int block_num; int per_block; int main() { int T; cin >> T; while (T--) { cin >> n >> m; for (int i = 0; i < n; ++i){ for (int j = 0; j < 5; ++j){ scanf("%d", &a[j][i].val); a[j][i].id = i; } } for (int i = 0; i < 5; ++i) sort(a[i], a[i] + n); block_num = sqrt(n + .0); per_block = ceil(n / (block_num + .0)); for (int i = 0; i < 5; ++i){ for (int k = 0; k < block_num; ++k){ bs[i][k].reset(); } } for (int i = 0; i < 5; ++i){ for (int j = 0; j < n; ++j){ bs[i][j / per_block].set(a[i][j].id); } } for (int i = 0; i < 5; ++i){ for (int j = 0; j < block_num; ++j){ if (j) bs[i][j] |= bs[i][j - 1]; } } cin >> q; int ans = 0; bitset<maxn> res, tmp; int d; while (q--) { res.set(); for (int k = 0; k < 5; ++k){ tmp.reset(); scanf("%d", &d); d ^= ans; int index = upper_bound(a[k], a[k] + n, Node(d, n + 1)) - a[k] - 1; if (index < 0){ res.reset(); continue; } if (index / per_block) { tmp = bs[k][index / per_block - 1]; } int start = (index / per_block)*per_block; int end = index; for (int i = start; i <= end; ++i){ tmp.set(a[k][i].id); } res &= tmp; } ans = res.count(); printf("%d\n", ans); } } return 0; }