2021杭电多校第一场 1006 xor sum

这篇博客介绍了一种利用字典树解决区间异或值大于等于k的最短区间问题。代码实现中,通过遍历每个数并插入字典树,同时更新最靠右的端点,然后查询满足条件的左端点。最后输出左端点和右端点。此方法适用于处理大量数据的区间查询问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意

给你n个数和k,问最短的区间长度,使得区间异或值>=k,输出左端点最小答案。

思路

对于每一个数,将其作为右端点,向左找满足条件的最靠右的左端点。
建立字典树,使用字典树完成上述操作。在插入元素时采用一个数组记录最靠右的端点。
清空操作在字典树中进行,防止超时

代码

#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
#define endl '\n'
ll gcd(ll a, ll b){
    return b == 0 ? a : gcd(b, a % b);
}
void input(){
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
}
inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
	while (c>='0'&&c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
	return x*f;
}
const int N = 1e5+10, M = N * 2, inf = 1e8;
int tr[N*32][2], idx, maxm[32*N];
ll n, a[N], t, k;
void insert(int x, int id){
    int p = 0;
    for(int i = 31; i >= 0; i--){
        int u = x >> i & 1; 
        if(!tr[p][u]) {
            tr[idx][0] = tr[idx][1] = 0; // 在字典树中清空
            maxm[idx] = 0;
            tr[p][u] = idx++;
        }
        p = tr[p][u];
        maxm[p] = max(maxm[p], id); // 记录最靠右的取值
    }
}
ll query(ll x){
    int p = 0, res = 0;
    for(int i = 31; i >= 0; i--){
        int vx = (x >> i) & 1;
        int vk = (k >> i) & 1;
        // 此处列举x和k的当前位取值,分情况讨论
        if(!vx){
            if(!vk){
                if(tr[p][1]) res = max(res, maxm[tr[p][1]]);
                p = tr[p][0];
            }else p = tr[p][1];
        }else {
            if(!vk){
                if(tr[p][0]) res = max(res, maxm[tr[p][0]]);
                p = tr[p][1];
            }else p = tr[p][0];
        }
        if(!p) break;
    }
    if(p) res = max(res, maxm[p]);
    return res;
}
int main(){
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    input();
    cin>>t;
    while(t--){
        tr[0][0] = tr[0][1] = 0; idx = 1;
        cin>>n>>k;
        for(int i = 1; i <= n; i++) cin>>a[i];
        for(int i = 1; i <= n; i++) a[i] ^= a[i-1];
        int ansL = 0, ansR = n;
        for(int i = 1; i <= n; i++){
            if((a[i]^a[i-1]) >= k) {
                ansL = i, ansR = i;
                break;
            }
            int nxtL = query(a[i]);
            if(nxtL > 0 && i - nxtL < ansR - ansL + 1){
                ansL = nxtL + 1;
                ansR = i;
            }
            insert(a[i], i);
        }
        if(ansL) cout<<ansL<<" "<<ansR<<endl;
        else cout<<-1<<endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值