首页 > 其他分享 >字典树(前缀树)求区间异或和(异或对)最大值

字典树(前缀树)求区间异或和(异或对)最大值

时间:2023-08-22 22:58:12浏览次数:34  
标签:前缀 int 最大值 ret son 异或

字典树(前缀树)求区间异或和(异或对)最大值

求子区间异或对最大值

求子区间异或对的最大值,利用前缀树可以在每次询问对子区间内的每个元素在O(log n)的时间内得到答案,执行n此的时间花费为O(n logn),而得到答案需要已经建立前缀树,而每次询问答案都需要重新建立一棵前缀树,每次建树最坏情况下的时间花费为O(n)。总的时间为O(n^2 logn),对于这题来说已经足够了。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

vector<vector<int>> son;
vector<int> a;
int idx;

void insert(int x){
    int p = 0;
    for(int i = 10; i >= 0; i--){
        int u = ((x >> i) & 1);
        if(!son[p][u]){
            son[p][u] = ++idx;
        }
        p = son[p][u];
    }
}

int query(int x){
    int p = 0;
    int ret = 0;
    for(int i = 10; i >= 0; i--){
        int u ((x >> i) & 1);
        if(son[p][!u]){
            ret = ret * 2 + 1;
            p = son[p][!u];
        }
        else{
            ret = ret * 2;
            p = son[p][u];
        }
    }
    return ret;
}

void solve(){
    int n, m;
    cin >> n >> m;
    a.resize(n + 1);
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }

    son.resize((n + 10) * 10, vector<int>(2));
    while(m--){
        idx = 0;
        int l, r;
        cin >> l >> r;
        for(int i = l; i <= r; i++){
            insert(a[i]);
        }

        int maxv = 0;
        for(int i = l; i <= r; i++){
            maxv = max(maxv, query(a[i]));
        }

        cout << maxv << endl;

        for(int i = 0; i < idx; i++){
            son[i][0] = son[i][1] = 0;
        }
    }

}

int main(){
    solve();
    return 0;
}

 

求子区间异或和最大值C. Vampiric Powers, anyone?

分析性质可以知道,只要求出子区间所能得到的最大异或和即可。而求一段连续子区间的异或和,可以利用前缀和:

s[n] = s[1] ^ s[2] ^ s[3] ^ ... ^ s[i] ^ s[i + 1] ^ ... ^ s[n]

s[i] = s[1] ^ s[2] ^ s[3] ^ ... ^ s[i] = s[n] ^ s[i - 1]

把这样处理得到的前缀和序列作为对象,求子区间异或和最大值的问题就被转换成了求区间异或对最大值问题。利用前缀树处理,就能在O(log n)的时间内得到子区间异或和的最大值。

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

vector<int> a;
vector<vector<int>> son;
int idx;

void insert(int x){
    int p = 0;
    for(int i = 8; i >= 0; i--){
        int u = ((x >> i) & 1);
        if(!son[p][u]){
            son[p][u] = ++idx;
        }
        p = son[p][u];
    }
}

int query(int x){
    int p = 0;
    int ret = 0;
    for(int i = 8; i >= 0; i--){
        int u = ((x >> i) & 1);
        if(son[p][!u]){
            ret = ret * 2 + 1;
            p = son[p][!u];
        }
        else{
            ret = ret * 2;
            p = son[p][u];
        }
    }
    return ret;
}

void solve(){
    idx = 0;
    int n;
    cin >> n;
    a.resize(n + 1);
    for(int i = 1; i <= n; i++){
        cin >> a[i];
        a[i] = a[i] ^ a[i - 1];
    }

    son.resize((n + 10) * 8, vector<int>(2));

    int maxv = 0;
    for(int i = 0; i <= n; i++){
        insert(a[i]);
        maxv = max(maxv, query(a[i]));
    }
    
    cout << maxv << endl;

    for(int i = 0; i <= idx; i++){
        son[i][0] = son[i][1] = 0;
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t = 1;
    cin >> t;
    while(t--){
        solve();
    }
    return 0;
}

 

标签:前缀,int,最大值,ret,son,异或
From: https://www.cnblogs.com/kurish/p/17649867.html

相关文章

  • P9236 [蓝桥杯 2023 省 A] 异或和之和题解
    思路题目给我们一个数组\(a\),那么我们可以算出其异或前缀和\(sum\)。我们知道,算出\([l,r]\)的异或和可以这样计算:\(sum_r\oplussum_{l-1}\)。那么问题就转换为了\(sum_{0\simn}\)这\(n+1\)个数字两两异或之和(当然\(sum_i\oplussum_j\)和\(sum_j\oplussum......
  • 二维前缀和和差分
    二维前缀和和差分1.二维前缀和\[s_{i,j}=s_{i-1,j}+s_{i,j-1}-s_{i-1,j-1}\]\[s_{x_2,y_2}-s_{x_1-1,y_2}-s_{x_2,y_1-1}+s_{x_1-1,y_1-1}\]前缀和推广例题:有\(n\)个数,找出\(n-1\)个数,使得最大公因数最大解法:枚举\(n\)个数,不选一个,找出前缀公约数和后缀公约数,然......
  • 选择冒泡插入排序 异或 二分 对数器
    算法时间复杂度O(x)空间复杂度O(x)数据状况是否影响时间复杂度表现选择排序n21否冒泡排序n21否插入排序n21是(最好情况下O(N))1.选择排序:遍历找出0~n-1最小的数放在0位置,遍历找出1~n-1最小的数放在1位置时间复杂度O(n2) 空间复杂度O(1)voidswap(vector<int>&nums,inti,intj......
  • 代码随想录算法训练营第十三天|单调数列:滑动窗口最大值(力扣239.)、优先级队列:前k个高
    单调数列:滑动窗口最大值(力扣239.)给定滑动窗口的范围,求每个滑动窗口范围内的最大值使用单调队列实现对于最大值数字前面的数字不存入数列,对于最大值数字后面的数字存入数列中单调队列中数字的大小呈递减顺序pop(value):如果窗口移除的元素等于单调队列的队口元素,则pop;否则什......
  • 『学习笔记』欧拉函数、莫比乌斯函数、高位前缀和、狄利克雷前后缀和
    欧拉函数定义又叫做\(\varphi\)函数,\(\varphi(x)\)用来描述不大于\(x\)且与\(x\)互素的数的个数。性质满足一切积性函数的性质。若\(a\botb\),则\(f(a\timesb)=f(a)\timesf(b)\).能用线性筛或埃氏筛求出。\(\text{from}\1\\text{to}\n\)中与......
  • 敏感词过滤算法实现(前缀树)
    前缀树前缀树是N叉树的一种特殊形式,也叫Trie、字典树、查找树。通常来说,一个前缀树是用来存储字符串的。前缀树的每一个节点代表一个字符串(前缀)。每一个节点会有多个子节点,通往不同子节点的路径上有着不同的字符。子节点代表的字符串是由节点本身的原始字符串,以及通往该子节......
  • 数据结构(哈夫曼树):判定编码方案是否为前缀编码
    前缀编码定义:(字符集中)任一编码都不是其它字符的编码的前缀(字符集中)任一编码都不是其它字符的编码的前缀(字符集中)任一编码都不是其它字符的编码的前缀重要的话说三遍!例:(1)找出下面不是前缀编码的选项A{1,01,000,001}B{1,01,011,010}C{0,10,110,11}D{0,1,00,11}第一步:看A中的第一个数1,看看其他......
  • npm 更改package.json 中依赖包前缀
    ~会匹配最近的小版本依赖包,比如~1.2.3会匹配所有1.2.x版本,但是不包括1.3.0^会匹配最新的大版本依赖包,比如^1.2.3会匹配所有1.x.x的包,包括1.3.0,但是不包括2.0.0 *这意味着安装最新版本的依赖包 推荐使用~ npmconfigsetsave-prefix='~'......
  • 【题解】洛谷 P9532 [YsOI2023] 前缀和
    原题链接【LGR-151-Div.2】洛谷8月月赛II&YsOI2023T1解题思路设有一序列a,其中a1 =a2,第k(≥3) 项为前k-1项的前缀和。可以发现前q项分别为第一项的20 倍,20 倍,21 倍,22 倍,23 倍…2q-3 倍,2q-2 倍。扩展到整个序列中,可得第i( ≥ 3)项一定为2i-2a1。......
  • 洛谷P9533 区间翻转区间异或和 题解
    原题:洛谷P9533一道性质题不难发现,区间翻转操作是没有用的(虽然比赛的时候想了好久www)首先,区间翻转要想对答案有贡献,一定是下边这种情况:三个连续的区间:\(A~|~B~|~C\)满足:\(B\oplusC=0,A\oplusC=0\)。将\(B∪C\)这个灵异区间进行翻转,使\(A\)和\(C\)合并到一起,会增加一......