异或之Kth[1] (可持久化二进制trie树)

    xiaoxiao2021-03-25  88

    【问题描述】

      给出n个非负整数A[1]..A[n],编程回答询问:

      1 k x:询问 x xor A[i] (1<=i<=n) 中第k小的值。

      2 k l r x:询问 x xor A[i] (l<=i<=r) 中第k小的值。

    【输入格式】

      第一行为整数n。   第二行为n个非负整数,表示A[1],A[2],…,A[n]。   第三行为整数m。   之后的m行,每行表示一种询问。

    【输出格式】

      对于每个询问,给出你的回答。

    【输入样例】

    5 1 2 3 4 5 2 1 4 3 2 2 3 5 2

    【输出样例】

    6 6

    【数据范围】

    n,m<=500000 A[i],x均在unsigned long long 范围,所有询问均合法

    【来源】

    Mr_he原创

    一道可持久化的二进制trie树,写法类似权值线段树的Kth,只需要记录每个点的下面包含多少个数就可以了。

    详细代码如下:

    #include<cstdlib> #include<cstdio> #include<cstring> #include<iostream> #include<vector> using namespace std; typedef unsigned long long ull; const int maxn=500005; int root[maxn],s[maxn*32]={0},ch[maxn*32][2]={0},cnt=0,n; void up(int x) { s[x]=s[ch[x][0]]+s[ch[x][1]]; } void in(int pre,int &now,int i,ull x) { now=++cnt; ch[now][0]=ch[pre][0]; ch[now][1]=ch[pre][1]; s[now]=s[pre]; if(i<0) {s[now]++;return;} int d=(x>>i)&1; in(ch[pre][d],ch[now][d],i-1,x); up(now); } ull read() { ull x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x; } ull find(int pre,int now,int i,int k,ull &x) { if(i<0) return 0; int d=(x>>i)&1; int t=s[ch[now][d]]-s[ch[pre][d]]; if(t<k) { return find(ch[pre][d^1],ch[now][d^1],i-1,k-t,x)+((ull)1<<i); } else return find(ch[pre][d],ch[now][d],i-1,k,x); } char q[50]; void out(ull x) { if(!x) putchar('0'); int tot=0; while(x) { q[++tot]=x; x/=10; } for(int i=tot;i>=1;i--) putchar(q[i]+'0'); putchar('\n'); return; } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); n=read(); ull x,ans; for(int i=1;i<=n;i++) { x=read(); in(root[i-1],root[i],63,x); } int l,r,k,id; int m=read(); while(m--) { id=read(); if(id==1) { k=read();x=read(); ans=find(root[0],root[n],63,k,x); } if(id==2) { k=read();l=read();r=read();x=read(); ans=find(root[l-1],root[r],63,k,x); } out(ans); } return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-15915.html

    最新回复(0)