Codechef Xor Queries(可持久化字典树)

题意:
给定一个初始时为空的整数序列(元素由1开始标号)以及一些询问:
类型0:在数组最后加入数字x
类型1:在区间[L,R]中找到数字y,最大化(x^y)
类型2:删除数组最后k个元素
类型3:在区间[L,R]中,统计小于等于x的元素个数
类型4:在区间[L,R]中,找到第k小的数
(M<=5e5,x<=5e5)


#include<cstdio>
#include<algorithm>
using namespace std;
const int N=5e5+100;

struct Trie{
    int ch[2],sum,dep;
}T[N*30];
int root[N],sz;

void insert(int &i,int d,int x,int v){
    T[++sz]=T[i],i=sz;
    T[i].dep=d+1;
    T[i].sum+=v;    //此时判断的是上一位的d
    if(d<0) return ;
    int p=(x>>d)&1;
    insert(T[i].ch[p],d-1,x,v);
}

void Query_max_xor(int L,int R,int d,int x,int &ans){
    if(d<0)     return ;
    int p=(x>>d)&1;
    if(T[ T[R].ch[p^1] ].sum-T[ T[L].ch[p^1] ].sum)
        ans+=(p^1)*(1<<d),Query_max_xor(T[L].ch[p^1],T[R].ch[p^1],d-1,x,ans);
    else    ans+=p*(1<<d),Query_max_xor(T[L].ch[p],T[R].ch[p],d-1,x,ans);
}

void Query_equal_to_x(int L,int R,int d,int x,int &ans){
    if(d<0)     {ans+=T[R].sum-T[L].sum;return ;}
    int p=(x>>d)&1;
    if(p==1)  ans+=T[ T[R].ch[0] ].sum-T[ T[L].ch[0] ].sum;
    Query_equal_to_x(T[L].ch[p],T[R].ch[p],d-1,x-p*(1<<d),ans);
}

void Query_kth(int L,int R,int d,int x,int &ans){
    if(d<0)     return ;
    int k=T[ T[R].ch[0] ].sum-T[ T[L].ch[0] ].sum;
    if(k>=x)    Query_kth(T[L].ch[0],T[R].ch[0],d-1,x,ans);
    else   ans+=(1<<d),Query_kth(T[L].ch[1],T[R].ch[1],d-1,x-k,ans);
}

int main(){
    int m,n=0,L,R,ans,op,x;
    while(scanf("%d",&m)!=EOF){
        sz=0,root[0]=0;
        while(m--){
            scanf("%d",&op);
            if(op==0){
                scanf("%d",&x);
                root[++n]=root[n-1];
                insert(root[n],23,x,1);
            }
            else if(op==1){
                scanf("%d%d%d",&L,&R,&x);
                Query_max_xor(root[L-1],root[R],23,x,ans=0);
                printf("%d\n",ans);
            }
            else if(op==2)
                scanf("%d",&x),n-=x;
            else if(op==3){
                scanf("%d%d%d",&L,&R,&x);
                Query_equal_to_x(root[L-1],root[R],23,x,ans=0);
                printf("%d\n",ans);
            }
            else if(op==4){
                scanf("%d%d%d",&L,&R,&x);
                Query_kth(root[L-1],root[R],23,x,ans=0);
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值