bzoj-3685 普通van Emde Boas树 权值线段树+快读!

来源:互联网 发布:株洲中车 知乎 编辑:程序博客网 时间:2024/05/19 02:02


普通van Emde Boas树

  题意不再赘述见题面:

设计数据结构支持:
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

 数据范围和操作数都是1e6级别的,所以普通的set或者treap用起来很方便的是会超时的,所以怎么解决呢?

因为拉的是有关权值线段树的专题,所以很容易想到这个,空间也不会爆,不用离散化,那么每个叶节点代表这个值是否出现过即可,每个节点储存当前区间的最值,只有操作5、6相对比较麻烦,如果前驱的话相当于求[0,x-1]中存在的数的最大值,反之求[x+1,n-1]的最小值,其他的操作比较简单。但写出来竟然TLE了,考虑到数据量比较大。于是加了个快读,8000+ms。荣神将递归改成循环式查找6000+ms,ORZ。

权值线段树+快速读:

const int N=1e6+10;inline char nc(){    static char buf[100000],*p1=buf,*p2=buf;    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}inline int sc(){    char ch=nc();    int sum=0;    while(!(ch>='0'&&ch<='9'))ch=nc();    while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc();    return sum;}struct node{    int l,r,num,mi,ma;} a[N<<2];int n,m,c[N];void pushup(int k){    a[k].num=a[k*2].num+a[k*2+1].num;    a[k].mi=min((a[k*2].num?a[k*2].mi:INF),(a[k*2+1].num?a[k*2+1].mi:INF));    a[k].ma=max((a[k*2].num?a[k*2].ma:0),(a[k*2+1].num?a[k*2+1].ma:0));}void build(int l,int r ,int k){    a[k].l=l,a[k].r=r,a[k].num=0,a[k].mi=INF,a[k].ma=0;    if(l==r)    {        a[k].ma=a[k].mi=l;        c[l]=0;        return ;    }    int mid=(l+r)/2;    build(l,mid,2*k);    build(mid+1,r,2*k+1);}void update(int id,int f,int k)//支持插入或删除{    if(a[k].l==id&&a[k].r==id)    {        if(f==1&&!a[k].num)        {            a[k].num^=1;            c[id]=1;        }        else if(f==2&&a[k].num)        {            a[k].num^=1;            c[id]=0;        }        return ;    }    int mid=(a[k].l+a[k].r)/2;    if(id<=mid) update(id,f,k*2);    else update(id,f,k*2+1);    pushup(k);}int query(int l,int r,int f,int k)//求前驱或后继{    if(r<l) return INF;    if(a[k].l==l&&a[k].r==r)    {        if(!a[k].num) return INF;        return f==1?a[k].ma:a[k].mi;    }    int mid=(a[k].l+a[k].r)/2;    if(r<=mid) return query(l,r,f,2*k);    if(l>mid) return query(l,r,f,2*k+1);    else    {        int tmp1=query(l,mid,f,2*k);        int tmp2=query(mid+1,r,f,2*k+1);        if(tmp1==INF&&tmp2!=INF) return tmp2;        else if(tmp1!=INF&&tmp2==INF) return tmp1;        return (f==1)?max(tmp1,tmp2):min(tmp1,tmp2);    }}int main(){    while(~scanf("%d%d",&n,&m))    {        build(0,n,1);        while(m--)        {            int x,y;            x=sc();            if(x==3||x==4)            {                if(!a[1].num) puts("-1");                else printf("%d\n",x==3?a[1].mi:a[1].ma);                continue;            }            y=sc();            if(x==1||x==2) update(y,x,1);            else if(x==7)            {                if(c[y]) puts("1");                else puts("-1");            }            else            {                int tmp=INF;                if(x==5) tmp=query(0,y-1,1,1);                else tmp=query(y+1,n-1,2,1);                if(tmp==INF) puts("-1");                else printf("%d\n",tmp);            }        }    }    return 0;}

荣神大佬:

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define MAX 1000010#define LEFT (pos << 1)#define RIGHT (pos << 1 | 1)using namespace std;  int range, asks, M;int tree[MAX << 2];  inline void Modify(int pos, int c){    tree[pos] += c;    for (; pos; pos >>= 1)        tree[pos] += c;}  inline int GetMin(int pos){    if (!tree[pos])        return 0;    while (pos <= M)    {        if (tree[LEFT])            pos = LEFT;        else            pos = RIGHT;    }    return pos - M;}  inline int GetMax(int pos){    if (!tree[pos])        return 0;    while (pos <= M)    {        if (tree[RIGHT])            pos = RIGHT;        else            pos = LEFT;    }    return pos - M;}  inline int GetPred(int x){    int pos = x + M;    while (1)    {        if (pos == 1)            return 0;        if (pos & 1 && tree[pos ^ 1])            return GetMax(pos ^ 1);        pos >>= 1;    }    return 0;}  inline int GetSucc(int x){    int pos = x + M;    while (1)    {        if (pos == 1)            return 0;        if (!(pos & 1) && tree[pos ^ 1])            return GetMin(pos ^ 1);        pos >>= 1;    }    return 0;}  int main(){    cin >> range >> asks;    for (M = 1; M <= range; M <<= 1)        ;    for (int x, flag, i = 1; i <= asks; ++i)    {        scanf("%d", &flag);        if (flag == 1)        {            scanf("%d", &x);            ++x;            if (!tree[M + x])                Modify(M + x, 1);        }        else if (flag == 2)        {            scanf("%d", &x);            ++x;            if (tree[M + x])                Modify(M + x, -1);        }        else if (flag == 3)            printf("%d\n", GetMin(1) - 1);        else if (flag == 4)            printf("%d\n", GetMax(1) - 1);        else if (flag == 5)        {            scanf("%d", &x);            ++x;            printf("%d\n", GetPred(x) - 1);        }        else if (flag == 6)        {            scanf("%d", &x);            ++x;            printf("%d\n", GetSucc(x) - 1);        }        else        {            scanf("%d", &x);            ++x;            printf("%d\n", tree[x + M] ? 1 : -1);        }    }    return 0;}