题意:给定n个五维空间上的点,以及m组询问,每组询问给出一个点,求五个维度都不大于它的点有多少个,强制在线。
神仙题
单独考虑每个维度,把所有点按这个维度上的大小排序,然后分成T块,每块用一个bitset记录这个块以及之前的块中包含的点的集合的前缀和,并用mx[i][j]来记录第i维上大小为j的点所对应的最右边的块。对于每个询问的点,也是单独考虑每个维度,找到每个维度上对应的块,把这个块之前的块的前缀和加上,然后再暴力加上这个块中所有当前维度不超过它的点,五个维度取个交集就行了。
预处理复杂度$O(n+\frac{nT}{B})$,单次询问复杂度$O(\frac{n}{T}+\frac{n}{B})$,总复杂度$O(n+\frac{nT}{B}+\frac{qn}{T}+\frac{qn}{B})$,理论上T=B(约为64)时复杂度最低。
1 #include2 using namespace std; 3 typedef long long ll; 4 const int N=5e4+100,M=64,inf=0x3f3f3f3f; 5 struct D { 6 int x,i; 7 bool operator<(const D& b)const { return x bs[5][N/M],ans,now;11 int solve(int* b) {12 ans.set();13 for(int i=0; i<5; ++i) {14 now.reset();15 int j=mx[i][b[i]];16 if(j>0)now|=bs[i][j-1];17 for(int k=L[j]; k <=b[i]; ++k)now.set(a[i][k].i);18 ans&=now;19 }20 return ans.count();21 }22 int main() {23 int T;24 for(scanf("%d",&T); T--;) {25 scanf("%d%d",&n,&m);26 memset(L,-1,sizeof L);27 memset(mx,0,sizeof mx);28 for(int j=0; j