题解 | #小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;

}
全部评论

相关推荐

01-17 18:15
已编辑
门头沟学院 前端工程师
从上午约我面试然后他迟到,然后中午发消息打电话给我说重约面试时间,我就该意识到。【管理不规范,只是这家公司最小的问题】他妈一个不是技术的人来给我技术面。。。连vvue什么?连react是什么?连普通的HTTP请求是什么?这些东西都不懂的人来给我做技术面,我真的。。。。他妈浪费我40分钟。。一天面了三场,这家公司属实牛逼。不停的问我说上班下班时间谁来派任务公司在哪个区发展怎么样,公司的管理模式什么样,培养机制怎么样带教负责什么。如果出bug了谁来负责。我真的求你了别闹了。我答了15分钟,我已经很不想回答了。然后他就问了我一些很招笑的面试问题。问我前端框架架构设计怎么设计,Websocket可以实现SSE吗??最后还要我硬说,为什么我们公司没转正?为什么?为什么?我说我怎么知道。。这是领导决定,又不是我决定,他说让我分析一下。。。我真的草了,这个人是来搞我的吗?我最后问我说这个没有技术面,他说他就是技术面虽然我今天面的另外两家也很逆天。一个人不停的吹牛,自己100人的公司是全国前几,吹牛了一个小时。我中途几次想跑,真的是底下玩手机在听他那吹牛。。然后最后来了句说,我承诺的东西要实现哦,不然的话,公司会追责的,我我请问我承诺了什么?从头到尾也没有说让我承诺什么。而且我只是作为一个小小的前端卡拉咪,应届生。我要承担什么??好崩溃。。好崩溃的,一天面了三场。两家1000-9999的公司。面试官问的都很傻逼,甚至有些东西我问他估计都答不出来。。&nbsp;我这是在干嘛呀?浪费我一天的时间,我的奶奶。。我本来是抱着说我很菜,我要面试中发现自己的问题,现在来看他妈的这三场面试,面试本身就是问题。。
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务