P4098 [HEOI2013]ALO 可持久化01Trie

$ \color{#0066ff}{ 题目描述 }$

Welcome to ALO ( Arithmetic and Logistic Online)。这是一个 VR MMORPG, 如名字所见,到处充满了数学的谜题

现在你拥有 n 颗宝石,每颗宝石有一个能量密度,记为 ai,这些宝石的能量 密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设 为 ai, ai+1, …, aj,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值 与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值 为 k,则生成的宝石的能量密度为 max{k xor ap | ap ≠ k , i ≤ p ≤ j}

现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最 大

\(\color{#0066ff}{输入格式}\)

第一行,一个整数 n,表示宝石个数

第二行,n 个整数,分别表示 a1 至 an,表示每颗宝石的能量密度,保证对于 i ≠ j 有 ai ≠ aj

\(\color{#0066ff}{输出格式}\)

输出一行一个整数,表示最大能生成的宝石能量密度

\(\color{#0066ff}{输入样例}\)

5
9 2 1 4 7

\(\color{#0066ff}{输出样例}\)

14

\(\color{#0066ff}{数据范围与提示}\)

【样例解释】

选择区间[1,5],最大值为 7 xor 9

【数据规模与约定】

对于 20%的数据有 n ≤ 100

对于 50%的数据有 n ≤ 2000

对于 100%的数据有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9

\(\color{#0066ff}{题解}\)

找异或最大值,显然是要01trie,但是肯定是有个区间限制的,所以用主席树套一下就行了

考虑每个数作为次小值的区间,可以开一个链表,遍历值的时候从小到大,这样两边都是比它大的,就可以快速找到影响区间,直接在trie上查询更新ans就行了

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
const int maxn = 50505;
struct node {
    node *ch[2];
    int num;
    node(int num = 0): num(num) { ch[0] = ch[1] = NULL; }
};
node *root[maxn];
int a[maxn], n, pre[maxn], nxt[maxn];
std::pair<int, int> mp[maxn];
void add(node *&o, node *lst, int dep, int val) {
    o = new node(), *o = *lst, o->num++;
    if(!dep) return;
    if(val & (1 << (dep - 1))) add(o->ch[1], lst->ch[1], dep - 1, val);
    else add(o->ch[0], lst->ch[0], dep - 1, val);
}
void init() {
    root[0] = new node();
    root[0]->ch[0] = root[0]->ch[1] = root[0];
}
void del(int x) {
    if(pre[x]) nxt[pre[x]] = nxt[x];
    if(nxt[x] != n + 1) pre[nxt[x]] = pre[x];
}
int query(node *x, node *y, int dep, int val) {
    if(!dep) return 0;
    if(val & (1 << (dep - 1))) {
        if(y->ch[0]->num != x->ch[0]->num) return query(x->ch[0], y->ch[0], dep - 1, val) | (1 << (dep - 1));
        else return query(x->ch[1], y->ch[1], dep - 1, val);
    }
    else {
        if(y->ch[1]->num != x->ch[1]->num) return query(x->ch[1], y->ch[1], dep - 1, val) | (1 << (dep - 1));
        else return query(x->ch[0], y->ch[0], dep - 1, val);
    }
}

int main() {
    n = in(); init();
    for(int i = 1; i <= n; i++) add(root[i], root[i - 1], 30, a[i] = in());
    for(int i = 1; i <= n; i++) {
        pre[i] = i - 1;
        nxt[i] = i + 1;
        mp[i] = std::make_pair(a[i], i);
    }
    nxt[n + 1] = n + 1;
    std::sort(mp + 1, mp + n + 1);
    int ans = 0;
    for(int i = 1; i <= n; i++) {
        int now = mp[i].second;
        int l = pre[now], r = nxt[now];
        int ll = pre[l], rr = nxt[r];
        ans = std::max(ans, query(root[ll], root[r - 1], 30, mp[i].first));
        ans = std::max(ans, query(root[ll], root[rr - 1], 30, mp[i].first));
        del(mp[i].second);
    }
    printf("%d\n", ans);
    return 0;
}

原文地址:https://www.cnblogs.com/olinr/p/10623686.html

时间: 2024-11-03 03:27:01

P4098 [HEOI2013]ALO 可持久化01Trie的相关文章

[BZOJ 3166]Alo 可持久化01Trie

这道题入门了 可持久化01Trie 可持久化Trie多数用来解决区间异或k值之类的操作,主要是由高位到低位按位贪心就可以了 其实和主席树是一样的,Trie本身也有前缀相减性,至于空间,动态开点就可以了. 当然我们需要记录每个节点的size 对于这道题,我们可以用线段树处理出每一个数作为次大值的区间,然后去区间的Trie里面查询异或最大值就可以了 #include<iostream> #include<cstdio> #include<cstring> #define p

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

BZOJ 3166 HEOI2013 ALO 可持久化trie+st表

题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3166(洛谷上也有) 题意概述: 给出一个序列,对于一个区间,其权值为区间中的次大值亦或区间中任意一个数的结果的最大值.求区间权值的最大值. 分析: 考虑每个点作为区间次大的状态,发现对于每个点至多有两个最长区间其为次大值(为了让异或结果最大当然是区间越长越好,选择最多),用二分+静态RMQ算出这两个区间再在可持久化trie上面贪心即可. 论如何现场yy可持久化数据结构23333(基于可

bzoj3166: [Heoi2013]Alo 可持久化字典树

左右两边的比i大的最近的两个值.然后可持久化字典树即可. #include<bits/stdc++.h> using namespace std; int maxn=0,n,root[1600000],a[50010],cnt=0,l[1600000],r[1600000],p1[50010][25],p2[50010][25],sum[1600000],ans=0,pans=0,l1[50010],r1[50010],l2[50010],r2[50010]; void add(int &am

BZOJ 3166 HEOI2013 Alo 可持久化Trie树

题目大意:给定一个不重复的序列a,在a中任选一个区间,求区间内的次大值与区间内的任意一个其它数的最大的异或值 首先我们枚举次大值 对于一个次大值 它可能选择的另一个数的取值范围为(l,r) 其中l为这个数左侧第二个比它大的数 r为这个数右侧第二个比它大的数 在这个区间内的Trie树中贪心寻找最大值即可 这个区间怎么求呢?我们维护一棵平衡树 将数从大到小将下标加进平衡树 每加进一个下标 比它大的数的下标都在平衡树中 求两次后继就是r 求两次前驱就是l 我偷懒写了set-- #include<set

BZOJ 3166: [Heoi2013]Alo

3166: [Heoi2013]Alo Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 923  Solved: 437[Submit][Status][Discuss] Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选

bzoj 4137 [FJOI2015]火星商店问题——线段树分治+可持久化01trie树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4137 关于可持久化01trie树:https://www.cnblogs.com/LadyLex/p/7281110.html 看了看它的两道例题,就没写. 特殊商品可以直接用可持久化trie做. 其他部分用线段树分治.修改是单点的,询问是区间,原来想的是把询问区间定位后有 mlogn 个,在线段树的每个叶子上贡献一番:结果TLE了,因为若是在叶子处贡献,一个询问就要做 r-l+1 次.

P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树

$ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 \(1\) 到 \(n\).第 \(i\) 种馅儿具有一个非负整数的属性值 \(a_i\).每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子.小粽准备用这些馅儿来做出 \(k\) 个粽子. 小粽的做法是:选两个整数数 \(l\), \(r\),满足 \(1 \leqslant l

可持久化0-1Trie树

我跟可持久化数据结构杠上了 \(QwQ\) .三天模拟赛考了两次可持久化数据结构(主席树.可持久化0-1Trie树),woc. 目录: 个人理解 时空复杂度分析 例题及简析 一.个人理解 可持久化0-1Trie树,是一种可以快速查询区间异或信息的高级数据结构. 它的主要思想和主席树相同,即保存每次插入操作的历史版本,来快速查询区间的异或信息. 0-1Trie树和平常写的strTrie树相同,都是维护前缀信息的数据结构.不同点只有一个,就是0-1Trie树是维护一个0-1串.可持久化0-1Trie