• bzoj3685 普通veb树


    Description

    设计数据结构支持:

    1 x  若x不存在,插入x

    2 x  若x存在,删除x

    3    输出当前最小值,若不存在输出-1

    4    输出当前最大值,若不存在输出-1

    5 x  输出x的前驱,若不存在输出-1

    6 x  输出x的后继,若不存在输出-1

    7 x  若x存在,输出1,否则输出-1

    Input

    第一行给出n,m 表示出现数的范围和操作个数

    接下来m行给出操作

    n<=10^6,m<=2*10^6,0<=x<n

    常规做法是用线段树,但根据这题的特点,还有很多其它数据结构可以用。

    将线段树和trie结合,可得每个结点有8个子结点的线段树,每个结点压位维护8个子树是否非空。

    预处理每个状态最左/右非空子树位置。

    插入或删除时自底向上修改。查询前驱后继时自底向上找到前驱或后继所在区间再向下找到其具体位置。

    最后加读入/输出优化,比zkw线段树略快一点,内存也省了很多。

    #include<cstdio>
    inline int read(){
        char c=getchar();
        int x=0;
        while(c>'9'||c<'0')c=getchar();
        while(c>='0'&&c<='9')
        x=x*10+c-'0',c=getchar();
        return x;
    }
    char str[16];
    inline void print(int x){
        if(!x){
            puts("0");
            return;
        }
        if(x<0)putchar('-'),x=-x;
        int p=0;
        while(x)str[p++]=x%10+'0',x/=10;
        while(p)putchar(str[--p]);
        putchar(10);
    }
    bool d[2097154];
    unsigned char ds[8][262144];
    int lp[256],rp[256];
    int ls[8],rs[8];
    inline void ins(int x){
        if(d[x])return;
        d[x]=1;
        for(int i=1;i<=7;i++)ds[i][x>>i*3]|=1<<((x>>i*3-3)&7);
    }
    inline void del(int x){
        if(d[x])d[x]=0;
        else return;
        for(int i=1;i<=7;i++)if(ds[i][x>>i*3]^=1<<((x>>i*3-3)&7))return;
    }
    inline int minv(){
        if(!ds[7][0])return -1;
        register int p=lp[ds[7][0]];
        for(int i=6;i;--i)p=(p<<3)+lp[ds[i][p]];
        return p;
    }
    inline int maxv(){
        if(!ds[7][0])return -1;
        register int p=rp[ds[7][0]];
        for(int i=6;i;--i)p=(p<<3)+rp[ds[i][p]];
        return p;
    }
    inline int prv(int p){
        if(!ds[7][0])return -1;
        register int s=ds[1][p>>3]&ls[p&7];
        if(s)return (p^(p&7))|rp[s];
        for(int i=2;i<=7;i++){
            p>>=3;
            s=ds[i][p>>3]&ls[p&7];
            if(s){
                p=(p^(p&7))|rp[s];
                for(int j=i-1;j;--j)p=(p<<3)|rp[ds[j][p]];
                return p;
            }
        }
        return -1;
    }
    inline int nxt(int p){
        if(!ds[7][0])return -1;
        register int s=ds[1][p>>3]&rs[p&7];
        if(s)return (p^(p&7))|lp[s];
        for(int i=2;i<=7;i++){
            p>>=3;
            s=ds[i][p>>3]&rs[p&7];
            if(s){
                p=(p^(p&7))|lp[s];
                for(int j=i-1;j;--j)p=(p<<3)|lp[ds[j][p]];
                return p;
            }
        }
        return -1;
    }
    int n,m,a,b;
    int main(){
        for(int i=1;i<256;i++){
            int j=0;
            while(!(i&1<<j))++j;
            lp[i]=j;
            j=7;
            while(!(i&1<<j))--j;
            rp[i]=j;
        }
        for(int i=0;i<8;i++)ls[i]=255>>8-i,rs[i]=255&(255<<i+1);
        n=read();
        m=read();
        for(int i=0;i<m;i++){
            a=read();
            if(a<3){
                b=read();
                if(a==1)ins(b);
                else if(a==2)del(b);
            }else if(a>4){
                b=read();
                if(a==5)print(prv(b));
                else if(a==6)print(nxt(b));
                else if(a==7)puts(d[b]&&ds[1][b>>3]&1<<(b&7)?"1":"-1");
            }else if(a==3)print(minv());
            else if(a==4)print(maxv());
            
        }
        return 0;
    }
  • 相关阅读:
    LeetCode --- 字符串系列 --- 解码字母到整数映射
    LeetCode --- 字符串系列 --- 上升下降字符串
    LeetCode --- 字符串系列 --- 机器人能否返回原点
    集合 Set
    LeetCode --- 字符串系列 --- 唯一摩尔斯密码词
    LeetCode --- 字符串系列 --- 转换成小写字母
    LeetCode --- 字符串系列 --- 分割平衡字符串
    LeetCode --- 字符串系列 --- IP 地址无效化
    LeetCode --- 字符串系列 --- 左旋转字符串
    Revit二次开发八 事务标签值
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5136771.html
Copyright © 2020-2023  润新知