01Trie

01Trie

结合板子 CF2093 来说

实际上和普通的字典树没有过多的区别,最大的区别在于操作的对象不同。

字典树是统计单词出现的数量。

01Trie是把数值转换成 \(01\) 串,从而在某种意义上将整数的比较和字典序联系起来,不难想到,这样一个数据结构可以做到平衡树能够做的大部分事情,并且可以有稳定的 \(O(n\log n)\) 复杂度,这得益于二进制划分的优越性。

CF2093

给定一个序列 \(a_n\) 和一个整数 \(k\) ,求一个 \(|i-j|\) 最小的,满足 \(a_i \oplus a_j\ge k\) 数对 $(i,j) $,只用输出 \(j-i+1\) 即可。

非常重要的一个性质就是,这个大小的比较,可以转换成:(对于 \(x\ge y\) 举例而言)

在位数足够的二进制表示下 ,存在一个从高到低数的位置 \(pos\) ,使得 \(\forall i\le pos,x_i=y_i\) ;并且在 \(pos\) 这个位置上面,有 \(x_{pos}>y_{pos}\) ,这时就有 \(x>y\)。对于 \(x<y\) 反之亦然。

如果从高到低位检查到最后,仍然没有出现不等关系,说明 \(x=y\)

(其实就是字典序的比较)

分析

对于这个题来说,\(O(n^2)\) 的暴力枚举肯定无法接受,非常容易想到的是,我们枚举其中一个,然后用一个数据结构或者是其他的算法去 \(log\) 地找到第二个。这个题里面也就是用 01Trie 了。

谨记刚刚提到的比较方法,我们的目标就是找到这样一个 \(pos\) ,于是我们枚举 \(a_j\)\(k\) 走到了哪一位 \(t\), 然后按照 \(a_{it}\oplus a_{jt}=k_t\) 来遍历字典树,什么时候能够取到 \(>\) ?显然当 \(k_t=0\) 的时候是有可能的,这时候我们检查一下 \(a_{jt}\oplus1\) 这个子节点的值就行。注意最后还要判断一下走到了最后也没能取到不等关系的情况。

Code

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;

int n,k[35];
int tr[N*35][2],val[N*35];
int cnt;
int x[N][35];
inline void clear()
{
    for(int i=0;i<=cnt;++i)tr[i][0]=tr[i][1]=val[i]=0;
    cnt=0;
}
inline void insert(int id)
{
    int p=0;
    for(int i=1;i<=32;++i)
    {
        if(!tr[p][x[id][i]])tr[p][x[id][i]]=++cnt;
        p=tr[p][x[id][i]];
        val[p]=max(val[p],id);
    }
}
inline void solve()
{
    cin>>n;
    int rd;
    cin>>rd;
    for(int j=32;j>=1;--j,rd>>=1)k[j]=rd&1;
    for(int i=1,rd;i<=n;++i)
    {
        cin>>rd;
        for(int j=32;j>=1;--j,rd>>=1)x[i][j]=rd&1;
    }
    int ans=N;
    for(int i=1;i<=n;++i)
    {
        insert(i);
        int p=0;
        int tmp=0;
        for(int j=1;j<=32;++j)
        {
            if(k[j]==0)
            {
                if(tr[p][x[i][j]^1])tmp=max(tmp,val[tr[p][x[i][j]^1]]);
            }
            p=tr[p][x[i][j]^k[j]];
            if(!p)goto NEX;
        }
        // cout<<p<<' ';
        tmp=max(tmp,val[p]);
        NEX:if(tmp)ans=min(ans,i-tmp+1);
    }
    // cout<<'\n';
    if(ans==N)cout<<"-1\n";
    else cout<<ans<<'\n';
    clear();
}
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int T;cin>>T;
    while(T--)solve();
    return 0;
}
posted @ 2025-04-10 17:07  Hanggoash  阅读(18)  评论(0)    收藏  举报
动态线条
动态线条end