题解 | #小Q与彼岸花#

小Q与彼岸花

https://ac.nowcoder.com/acm/problem/219166

题意:
在这里插入图片描述
题解:因为这个题目是弱化以后的,正常的范围是5e4 .
看了官方题解去学习了一波可持久化01trie然后回来把这个题补完。

可持久数据结构其实就是我们的数据结构的内容会不断发生变化,而我们还要查询以前的历史版本,比如某个区间的情况。

听名字可以听出来,可持久化01trie跟可持久化线段树差不多的效果,对于01字典树来说,可以指定查询 范围内的数组成的字典树。

但是针对于这个题目我们直接使用可持久化01trie进行维护,时间还是不能被允许的,所以说, 我们还需要去继续优化。

如何优化呢? 分块!
我们用数组预处理出来 块x到块y之间的区间任意两数的最大异或值。

时间复杂度呢?

我们把数组分成大小为的块,那么可以分成个块
所以预处理的复杂度为: (类似于区间求解众数--强制在线)
应该没错。。。

for(int i=1;i<=sumblocks;i++){
    for(int j=i;j<=sumblocks;j++){
        int nowmax=ans[i][j-1];
        for(int k=(j-1)*sz+1;k<=min(n,j*sz);k++){
            int res=query(rt[min(j*sz,n)],a[k],(i-1)*sz+1);
            nowmax=max(nowmax,res);
        }
        ans[i][j]=nowmax;
    }
}

然后对于每次查询,如果l和r属于同一个块之间,那么我们直接暴力即可
那么如果不在同一个块呢,那么就跟最简单的分块一样了,先让最大值等于中间完整的块,然后我们暴力处理一下两边不全的块并不断更新最大值,然后返回最大值即可。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e6+10;


int ans[300][300];
int a[maxn],buck[maxn];
int rt[maxn];
int sz,idx;
int trie[maxn*20][2];
int max_id[maxn];


void ins(int x,int pre,int now){
    for(int i=12;i>=0;i--){
        max_id[now]=x;
        int val=(a[x]>>i)&1;
        trie[now][val^1]=trie[pre][val^1];
        trie[now][val]=++idx;
        now=idx;
        pre=trie[pre][val];
    }
    max_id[now]=x;
}

int query(int root,int C,int L){
    int p=root;
    for(int i=12;i>=0;i--){
        int val=(C>>i)&1;
        if(max_id[trie[p][val^1]]>=L) p=trie[p][val^1];
        else p=trie[p][val];
    }
    return C^a[max_id[p]];
}

int get_block(int x){
    return (x-1)/sz+1;
}

int sol(int l,int r){
    int st=get_block(l);
    int ed=get_block(r);
    if(st==ed){
        int imax=0;
        for(int i=l;i<=r;i++){
            imax=max(imax,query(rt[r],a[i],l));
        }
        return imax;
    }
    else{
        int imax=ans[st+1][ed-1];
        //cout<<"debug   "<<imax<<endl;
        for(int i=l;i<=st*sz;i++){
            imax=max(imax,query(rt[r],a[i],l));
        }
        for(int i=(ed-1)*sz+1;i<=r;i++){
            imax=max(imax,query(rt[r],a[i],l));
        }
        return imax;
    }
}


int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int n,m;
    cin>>n>>m;
    sz=sqrt(n);
    for(int i=1;i<=n;i++){
        cin>>a[i];
        rt[i]=++idx;
        ins(i,rt[i-1],rt[i]);
    }
    int sumblocks=(n-1)/sz+1;

    for(int i=1;i<=sumblocks;i++){
        for(int j=i;j<=sumblocks;j++){
            int nowmax=ans[i][j-1];
            for(int k=(j-1)*sz+1;k<=min(n,j*sz);k++){
                int res=query(rt[min(j*sz,n)],a[k],(i-1)*sz+1);
                nowmax=max(nowmax,res);
            }
            ans[i][j]=nowmax;
        }
    }

    while(m--){
        int l,r;
        cin>>l>>r;
        int xxx=sol(l,r);
        cout<<xxx<<endl;
    }
    return 0;

}
全部评论

相关推荐

点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务