• 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
    ", ans);
    	return 0;
    }
    
  • 相关阅读:
    SwiftUI:看我展示52张扑克牌,“很快啊!”
    不会吧,这也行?iOS后台锁屏监听摇一摇
    分布式锁
    布隆过滤器原理
    redis缓存穿透
    布隆过滤器应用DEMO
    线程的声明周期
    分布式事务
    滑动窗口协议
    代理
  • 原文地址:https://www.cnblogs.com/olinr/p/10623686.html
Copyright © 2020-2023  润新知