CodeChef XRQRS - Xor Queries

CodeChef XRQRS - Vjudge

题目简述
给出一个一维数组和若干个不同类型的询问:
• 0 x :在数组的最后添加 x
• 1 L R x :在区间 [L,R] 中找到 y,使 x xor y 最大
• 2 k :删除数组的最后 k 个数
• 3 L R x :统计区间 [L,R] 中有多少个数 y 小于或等于 x
• 4 L R k :找出区间 [L,R] 中从小到大的第 k 个数


题解

将每一个数按照其二进制插入 TRIE 中,维护前缀的 TRIE 树总和。

对于每一个询问,在两棵TRIE 上由上至下的走就可以了。


#include<iostream>
#include<cstdio>
#include<cstring>

#define ll long long
using namespace std;
const int N = 500000 + 10;
int rt[N];
int siz[N],son[N][2];
int tot;
int m;
int n;
void change(int &x, int xx, int d, int p){
    x = ++tot;
    memcpy(son[x], son[xx], sizeof(son[x]));
    siz[x] = siz[xx] + 1;
    if(d < 0)
        return ;
    if((p >> d-1) & 1)
        change(son[x][1], son[xx][1], d-1, p);
    else
        change(son[x][0], son[xx][0], d-1, p);
}
int query1(int x, int xx, int d, int y){
    if(d < 0)
        return 0;
    bool z = (y >> d-1) & 1 ^ 1;
    if(siz[son[xx][z]] - siz[son[x][z]])
        return (1 << d-1) + query1(son[x][z], son[xx][z], d-1, y);
    else
        return query1(son[x][z^1], son[xx][z^1], d-1, y);
}
int query2(int x, int xx, int d, int now, int y){
    if(d<0)
        return 0;
    if(y >= now + (1 << d-1))
        return siz[son[xx][0]] - siz[son[x][0]] + query2(son[x][1], son[xx][1], d-1, now+(1 << d-1), y);
    else
        return query2(son[x][0], son[xx][0], d-1, now, y);
}
int query3(int x,int xx,int d,int k){
    if(d < 0)
        return 0;
    int t = siz[son[xx][0]] - siz[son[x][0]];
    if(k <= t)
        return query3(son[x][0], son[xx][0], d-1, k);
    else
        return (1 << d-1) + query3(son[x][1], son[xx][1], d-1, k-t);
}
int main(){
    int o, x, y, z;
    scanf("%d", &m);
    while(m--){
        scanf("%d", &o);
        if(o == 0){
            scanf("%d", &x);
            change(rt[++n], rt[n], 19 ,x);
        }
        if(o == 1){
            scanf("%d%d%d",&x,&y,&z);
            printf("%d\n",z^query1(rt[x-1],rt[y],19,z));
        }
        if(o == 2){
            scanf("%d", &x);
            n -= x;
            tot = rt[n+1] - 1;
        }
        if(o == 3){
            scanf("%d%d%d", &x, &y, &z);
            printf("%d\n", query2(rt[x-1], rt[y], 19, 0, z));
        }
        if(o == 4){
            scanf("%d%d%d", &x,&y,&z);
            printf("%d\n", query3(rt[x-1], rt[y], 19, z));
        }
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值