• HihoCoder


    题目链接

    题意:给定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 #include<bits/stdc++.h>
     2 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<b.x;}
     8 } a[5][N];
     9 int n,m,k,sqrtn,in[N],mx[5][N],L[N/M],R[N/M],nb;
    10 bitset<N> 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<n&&a[i][k].x<=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<n; ++j) {nb=(in[j]=j/M)+1; if(!~L[in[j]])L[in[j]]=j; R[in[j]]=j;}
    29         for(int i=0; i<5; ++i)for(int j=0; j<nb; ++j)bs[i][j].reset();
    30         for(int i=0; i<n; ++i)
    31             for(int j=0; j<5; ++j)scanf("%d",&a[j][i].x),a[j][i].i=i;
    32         for(int i=0; i<5; ++i)sort(a[i],a[i]+n);
    33         for(int i=0; i<5; ++i) {
    34             for(int j=0; j<n; ++j) {
    35                 mx[i][a[i][j].x]=in[j];
    36                 bs[i][in[j]].set(a[i][j].i);
    37             }
    38             for(int j=2; j<=m; ++j)mx[i][j]=max(mx[i][j],mx[i][j-1]);
    39             for(int j=1; j<nb; ++j)bs[i][j]|=bs[i][j-1];
    40         }
    41         scanf("%d",&k);
    42         for(int ans=0; k--;) {
    43             int b[5];
    44             for(int i=0; i<5; ++i)scanf("%d",&b[i]),b[i]^=ans;
    45             printf("%d
    ",ans=solve(b));
    46         }
    47     }
    48     return 0;
    49 }
  • 相关阅读:
    [CQOI2017] 小Q的棋盘
    CF75D Big Maximum Sum
    Dockerfile
    docker镜像与容器的导出导入
    ubuntu安装glusterFS
    常用工具网站网址
    国内数据分析平台
    清理系统垃圾
    sql注入笔记
    shopify Liquid语言学习知识点总结
  • 原文地址:https://www.cnblogs.com/asdfsag/p/10672360.html
Copyright © 2020-2023  润新知