LeetCode 5696. 统计异或值在范围内的数对有多少(字典树)

题意:
给你一个整数数组 nums (下标 从 0 开始 计数)以及两个整数:low 和 high ,请返回 漂亮数对 的数目。

漂亮数对 是一个形如 (i, j) 的数对,
其中 0 <= i < j < nums.length 且 low <= (nums[i] XOR nums[j]) <= high 。

数据范围:
1 <= nums.length <= 2 * 1e4
1 <= nums[i] <= 2 * 1e4
1 <= low <= high <= 2 * 1e4
解法:
题目是对于每个j,查询有多少个i,满足lc<=(a[i]^a[j])<=rc.f(x)为与a[j]异或<=x的i的数量,那么可以将问题变为:
对于每个j,查询f(rc)-f(lc-1),
f(rc)可以通过在字典树上dfs实现.
code:
const int maxm=1e5+5;
struct TT{
    int a[maxm][32],tot;
    int cnt[maxm];
    void init(){
        for(int i=0;i<=tot;i++){
            memset(a[i],0,sizeof a[i]);
            cnt[i]=0;
        }
        tot=0;
    }
    void add(int x){
        int node=0;
        for(int i=30;i>=0;i--){
            int v=(x>>i&1);
            if(!a[node][v])a[node][v]=++tot;
            node=a[node][v];
            cnt[node]++;
        }
    }
    int ask(int x,int ma){//计算与x异或之后<=ma的有多少个
        if(ma<0)return 0;
        int node=0;
        int ans=0;
        for(int i=30;i>=0;i--){
            int v=(x>>i&1);
            int vv=(ma>>i&1);
            if(v&&vv){//11
                ans+=cnt[a[node][1]];//选1一定小于
                node=a[node][0];
            }else if(v&&!vv){//10
                node=a[node][1];//必须选1
            }else if(!v&&vv){//01
                ans+=cnt[a[node][0]];//选0一定小于
                node=a[node][1];
            }else if(!v&&!vv){//00
                node=a[node][0];//必须选0
            }
            if(!node)return ans;//如果没有等于得路线,就不能继续走了.
        }
        ans+=cnt[node];//等于
        return ans;
    }
}T;
class Solution {
public:
    int countPairs(vector<int>& a, int lc, int rc) {
        T.init();
        int n=a.size();
        int ans=0;
        T.add(a[0]);
        for(int i=1;i<n;i++){
            int t=T.ask(a[i],rc)-T.ask(a[i],lc-1);
            cout<<i<<' '<<t<<endl;
            ans+=t;
            T.add(a[i]);
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值