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;
}

  

posted @ 2015-09-22 18:13  chanme  阅读(270)  评论(0编辑  收藏  举报