BZOJ 3685 zkw线段树 || 权值线段树

来源:互联网 发布:windows无法访问文件夹 编辑:程序博客网 时间:2024/06/04 18:49

题目链接


思路:
七个操作显然都可以用Treap来维护,但编程复杂度很高,而且似乎此题数据也故意卡Treap

前几个操作都很简单,主要复杂于前驱和后继的高效维护。

考虑建立一棵权值线段树,对于值val的前驱和线段树当前节点rt
valrt的左儿子区间,则直接递归到左儿子去找前驱。
valrt的右儿子区间,则前驱有两种可能,一是在右儿子区间中val值的前一个值,二是可能为左儿子区间的最大值。

分情况讨论即可,对于后继同理。

加上读入挂,8000ms勉强卡过。

这里写图片描述


而上面3000ms的代码,则使用的是zkw线段树。
因为此题只需要维护前缀和,且自下往上的查找前驱和后继的方式更加快速,并且zkw线段树在内存和编程复杂度上,均比普通的权值线段树简单很多。

代码:
普通权值线段树:

#include<cstdio>using namespace std;#define lson rt<<1#define rson rt<<1|1inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const int A = 1e6 + 10;class Seg_Tree{public:    int l,r,val;}Tree[A<<2];int n,m,op,x;inline void push_up(int rt){Tree[rt].val = Tree[lson].val + Tree[rson].val;}void build(int rt,int l,int r){    Tree[rt].l = l,Tree[rt].r = r;Tree[rt].val = 0;    if(l == r) return;    int mid = (l+r)>>1;    build(lson,l,mid);build(rson,mid+1,r);    push_up(rt);}void update(int rt,int v,int c){    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r){Tree[rt].val = c;return;}    int mid = (l+r)>>1;    if(v<=mid) update(lson,v,c);    else       update(rson,v,c);    push_up(rt);}int Mn(int rt){    if(!Tree[rt].val) return -1;    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r) return l;    if(Tree[lson].val) return Mn(lson);    else               return Mn(rson);}int Mx(int rt){    if(!Tree[rt].val) return -1;    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r) return l;    if(Tree[rson].val) return Mx(rson);    else               return Mx(lson);}int Find(int rt,int val){    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r){        if(Tree[rt].val) return 1;        else             return -1;    }    int mid = (l+r)>>1;    if(val<=mid) return Find(lson,val);    else         return Find(rson,val);}int Find_pr(int rt,int val){    if(val<0 || !Tree[rt].val) return -1;    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r) return l;    int mid = (l+r)>>1;    if(val <= mid) return Find_pr(lson,val);    else{        int tem = Find_pr(rson,val);        if(tem == -1) return Mx(lson);        return tem;    }}int Find_su(int rt,int val){    if(!Tree[rt].val) return -1;    int l = Tree[rt].l,r = Tree[rt].r;    if(l == r) return l;    int mid = (l+r)>>1;    if(val>mid) return Find_su(rson,val);    else{        int tem = Find_su(lson,val);        if(tem == -1) return Mn(rson);        return tem;    }}int main(){    n = read();m = read();    build(1,0,n);    for(int i=1 ;i<=m ;i++){        op = read();        if(op == 1){x=read();update(1,x,1);}else        if(op == 2){x=read();update(1,x,0);}else        if(op == 3){printf("%d\n",Mn(1));}  else        if(op == 4){printf("%d\n",Mx(1));}  else        if(op == 5){x=read();printf("%d\n",Find_pr(1,x-1));}else        if(op == 6){x=read();printf("%d\n",Find_su(1,x+1));}else        if(op == 7){x=read();printf("%d\n",Find(1,x));}    }    return 0;}

zkw线段树:

#include<cstdio>using namespace std;#define lson rt<<1#define rson rt<<1|1#define fa   rt>>1inline int read(){    int x=0,f=1;char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const int A = 1<<20;int Tree[A<<1|1],M,n,m,op,x;bool vis[A];void update(int rt,int v){for(rt+=M;rt;rt=fa) Tree[rt]+=v;}int Mn(int rt){for(;rt<=M;rt=Tree[lson]?lson:rson);return rt-M-1;}int Mx(int rt){for(;rt<=M;rt=Tree[rson]?rson:lson);return rt-M-1;}int Find_pr(int rt){for(rt+=M ;rt!=1 ;rt=fa){if((rt&1) && Tree[rt^1]) return Mx(rt^1);}return -1;}int Find_su(int rt){for(rt+=M ;rt!=1 ;rt=fa){if(!(rt&1)&& Tree[rt^1]) return Mn(rt^1);}return -1;}int main(){    n = read();m = read();    for(M=1 ;M<=n ;M<<=1);    for(int i=1 ;i<=m ;i++){        op = read();        if(op==1){if(!vis[x=read()+1]) vis[x]=1,update(x,1);}else        if(op==2){if(vis[x=read()+1]) vis[x]=0,update(x,-1);}else        if(op==3){printf("%d\n",Tree[1]?Mn(1):-1);}else        if(op==4){printf("%d\n",Tree[1]?Mx(1):-1);}else        if(op==5){printf("%d\n",Find_pr(read()+1));}else        if(op==6){printf("%d\n",Find_su(read()+1));}else        if(op==7){printf("%d\n",vis[read()+1]?1:-1);}    }    return 0;}
原创粉丝点击