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
59 2 1 4 7
Sample Output
14HINT
【樣例解釋】
選擇區間[1,5],最大值為 7 xor 9。
對於 100%的數據有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9
Source
加強型數據By Hta
又是一道大坑啊……
習慣了求區間最大值,區間次大值怎麽求呢?本題的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 }View Code
Bzoj 3166 [Heoi2013] Alo 題解