NEFU 1270 智力异或(2)|| 2017icpc青岛站 热身赛 C (01字典树)

来源:互联网 发布:php 断点续传 编辑:程序博客网 时间:2024/06/04 19:02

题意:

中文

思路:

将数插入到01字典树中并记录子树的大小和子树中所有数的位信息。

查询时在字典树中搜索前K个即可。

注意数是可以重复的

代码:

#include <iostream>#include <cstring>#include <cstdio>using namespace std;const int MAXN=1e5+7;int n,m,p;int ls[MAXN*35]={0},rs[MAXN*35]={0},num[MAXN*35]={0},bit[MAXN*35][32]={0};int cnt=0;long long two[32];int trans(int rt){    if(rt==0){        ++cnt;        return cnt;    }    return rt;}void ini(){    for(int i=0;i<=cnt;i++){        ls[i]=rs[i]=num[i]=0;        for(int j=0;j<32;j++) bit[i][j]=0;    }    cnt=1;p=0;}void insert(int x){    int rt=1;    num[rt]++;    for(int i=31;i>=0;i--) bit[rt][i]+=(x>>i)%2;    for(int i=31;i>=0;i--){        int c=(x>>i)%2;        if(c==0){            ls[rt]=trans(ls[rt]);            rt=ls[rt];            num[rt]++;            for(int j=31;j>=0;j--) bit[rt][j]+=(x>>j)%2;        }else{            rs[rt]=trans(rs[rt]);            rt=rs[rt];            num[rt]++;            for(int j=31;j>=0;j--) bit[rt][j]+=(x>>j)%2;        }    }}long long query(int x,int k){    int rt=1;    long long ans=0;    for(int i=31;i>=0&&k;i--){        int c=(x>>i)%2;        if(c==0){            if(rs[rt]){                if(num[rs[rt]]<=k){                    k-=num[rs[rt]];                    for(int j=31;j>=0;j--){                        int p=(x>>j)%2;                        if(p==0){                            ans+=bit[rs[rt]][j]*two[j];                        }else{                            ans+=(num[rs[rt]]-bit[rs[rt]][j])*two[j];                        }                    }                    rt=ls[rt];                }else{                    rt=rs[rt];                }            }else{                rt=ls[rt];            }        }else{            if(ls[rt]){                if(num[ls[rt]]<=k){                    k-=num[ls[rt]];                    for(int j=31;j>=0;j--){                        int p=(x>>j)%2;                        if(p==0){                            ans+=bit[ls[rt]][j]*two[j];                        }else{                            ans+=(num[ls[rt]]-bit[ls[rt]][j])*two[j];                        }                    }                    rt=rs[rt];                }else{                    rt=ls[rt];                }            }else{                rt=rs[rt];            }        }    }    if(k){        for(int i=31;i>=0;i--){            int p=(x>>i)%2;            if((p==0&&bit[rt][i])||(p==1&&!bit[rt][i])){                ans+=k*two[i];            }        }    }    return ans;}int main(){    int T;    //freopen("data.in","r",stdin);    //freopen("out.txt","w",stdout);    two[0]=1;    for(int i=1;i<32;i++) two[i]=two[i-1]*2;    scanf("%d",&T);    while(T--){        scanf("%d%d",&n,&m);        ini();        for(int i=1;i<=n;i++){int x;scanf("%d",&x);            insert(x);        }        while(m--){int op,x;scanf("%d%d",&op,&x);            if(op==1){                p^=x;            }else{                printf("%lld\n",query(p,x));            }        }    }}


原创粉丝点击