Bzoj 3166 [Heoi2013] Alo 题解
Posted Hzoi_joker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Bzoj 3166 [Heoi2013] Alo 题解相关的知识,希望对你有一定的参考价值。
3166: [Heoi2013]Alo
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1118 Solved: 518
[Submit][Status][Discuss]
Description
Welcome to ALO ( Arithmetic and Logistic Online)。这是一个VR MMORPG ,
如名字所见,到处充满了数学的谜题。
现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量
密度两两不同。现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为 ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值
与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值
为k,则生成的宝石的能量密度为max{k xor ap | ap ≠ k , i ≤ p ≤ j}。
现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。
Input
第一行,一个整数 n,表示宝石个数。
第二行, n个整数,分别表示a1至an,表示每颗宝石的能量密度,保证对于i ≠ j有 ai ≠ aj。
Output
输出一行一个整数,表示最大能生成的宝石能量密度。
Sample Input
9 2 1 4 7
Sample Output
HINT
【样例解释】
选择区间[1,5],最大值为 7 xor 9。
对于 100%的数据有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9
Source
又是一道大坑啊……
习惯了求区间最大值,区间次大值怎么求呢?本题的n并不允许我们枚举区间,因此我们需要去求出每一个点的可选范围。既然该点是作为次大值出现在区间里,那么我们就要保证区间里有且只有一个比他大的。那么,他的取值范围就是他向左数第2个比他大的数+1~他向右数第2个比他大的数-1。当时看黄学长的时候黄学长说“前驱的前驱”脑子没反应过来,还以为是对他的前驱而言的前驱……
区间知道了,那么怎么求最大值呢?如果说这道题我们不需要求这么多次区间异或最大值我们可以使用01trie树进行贪心。然而,由于这里我们要求好多次,普通的01trie并没有什么用,我们需要的是一个支持区间求异或最大值的数据结构——可持久化01trie.
其实可持久化01trie打起来和不带修改的主席树没有太大的差别。毕竟都是二叉树。如果没有打过可以先去打一下主席树的模板题,求区间第K大。
插入操作基本不变。在查询的时候我们利用前缀和,能让他异或后该位为1,且在这个区间里有满足要求的数,我们就选上并且沿着trie树向那个方向走,否则就向另一个方向走,可以把它理解为一个特殊的在trie树上的dfs。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <cmath> 7 #include <queue> 8 #include <set> 9 #include <vector> 10 #define N 50006 11 #define lowbit(x) (x&(-x)) 12 using namespace std; 13 int n,a[N],b[N]; 14 set<int> q; 15 struct node{ 16 int size; 17 node* ch[2]; 18 node() { 19 size=0; 20 ch[1]=ch[0]=0; 21 } 22 }*null=new node(),*root[N]; 23 node* newnode() 24 { 25 node* x=new node(); 26 x->ch[0]=x->ch[1]=null; 27 return x; 28 } 29 void insert(node* la,node* now,int js,int x) 30 { 31 now->size=la->size+1; 32 if(!js)return; 33 if(x&(1ll<<(js-1))) 34 { 35 now->ch[0]=la->ch[0]; 36 now->ch[1]=newnode(); 37 insert(la->ch[1],now->ch[1],js-1,x); 38 } 39 else 40 { 41 now->ch[1]=la->ch[1]; 42 now->ch[0]=newnode(); 43 insert(la->ch[0],now->ch[0],js-1,x); 44 } 45 } 46 long long que(node* l,node* r,int x) 47 { 48 long long ans=0; 49 for(int i=32;i>=1;i--) 50 { 51 if(x&(1ll<<(i-1))) 52 { 53 if(r->ch[0]->size-l->ch[0]->size) 54 { 55 ans|=(1ll<<(i-1)); 56 l=l->ch[0]; 57 r=r->ch[0]; 58 } 59 else 60 { 61 r=r->ch[1]; 62 l=l->ch[1]; 63 } 64 } 65 else 66 { 67 if(r->ch[1]->size-l->ch[1]->size) 68 { 69 ans|=(1ll<<(i-1)); 70 l=l->ch[1]; 71 r=r->ch[1]; 72 } 73 else 74 { 75 r=r->ch[0]; 76 l=l->ch[0]; 77 } 78 } 79 } 80 return ans; 81 } 82 bool px(int x,int y) 83 { 84 return a[x]>a[y]; 85 } 86 int main() 87 { 88 null->ch[0]=null->ch[1]=null; 89 root[0]=newnode(); 90 scanf("%d",&n); 91 for(int i=1;i<=n;i++) 92 { 93 root[i]=newnode(); 94 scanf("%d",&a[i]); 95 insert(root[i-1],root[i],32,a[i]); 96 b[i]=i; 97 } 98 sort(b+1,b+n+1,px); 99 long long ans=0; 100 q.insert(-2);q.insert(-1); 101 q.insert(1000000002);q.insert(1000000003); 102 q.insert(b[1]); 103 for(int i=2;i<=n;i++) 104 { 105 set<int>::iterator it,p; 106 p=it=q.lower_bound(b[i]); 107 int r,l; 108 it++;r=*it-1; 109 p--;p--; l=*p+1; 110 l=max(l,1);r=min(r,n); 111 if(l!=r)ans=max(ans,que(root[l-1],root[r],a[b[i]])); 112 q.insert(b[i]); 113 } 114 printf("%lld\n",ans); 115 return 0; 116 }
以上是关于Bzoj 3166 [Heoi2013] Alo 题解的主要内容,如果未能解决你的问题,请参考以下文章
bzoj3166: [Heoi2013]Alo 可持久化字典树
BZOJ 3166 HEOI2013 ALO 可持久化trie+st表