【BZOJ】【3166】【HEOI2013】Alo
可持久化Trie+set
Orz zyf……
搞区间中次大值不好搞,那么我们就反过来,找一个数,然后看它在哪些区间里是次大值……
(然而事实上我们并不用真的把这个区间具体是什么找见,只要知道它可以跟哪一段数搞Xor就可以了!
而这个区间就是……左边第二个比他大的数的位置+1 ~ 右边第二个比它大的数的位置-1
这中间所有数都可以跟它搞Xor= =,我们总能找到一个相应的区间……
(我一开始理解成,这个区间就是我们要找的,a[i]为次大数的区间,然而这不是左边有一个比它大的,右边也有一个比它大的吗?但事实上我们是直接找了能跟a[i]搞Xor的区间(并)……
1 /************************************************************** 2 Problem: 3166 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:796 ms 7 Memory:28112 kb 8 ****************************************************************/ 9 10 //BZOJ 3166 11 #include<cstdio> 12 #include<set> 13 #include<cstring> 14 #include<cstdlib> 15 #include<iostream> 16 #include<algorithm> 17 #define rep(i,n) for(int i=0;i<n;++i) 18 #define F(i,j,n) for(int i=j;i<=n;++i) 19 #define D(i,j,n) for(int i=j;i>=n;--i) 20 #define pb push_back 21 using namespace std; 22 typedef long long LL; 23 inline int getint(){ 24 int r=1,v=0; char ch=getchar(); 25 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 26 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 27 return r*v; 28 } 29 const int N=100010,M=2000010; 30 /*******************template********************/ 31 32 int n,mx,a[N],t[M][2],rt[N],id[M],tot; 33 set<int>s; 34 set<int>::iterator it; 35 typedef pair<int,int> pii; 36 pii b[N]; 37 int l[N],r[N]; 38 39 inline void Ins(int pre,int x,int k){ 40 int now=rt[k]=++tot; id[tot]=k; 41 D(i,30,0){ 42 int j=(x>>i)&1; 43 t[now][j^1]=t[pre][j^1]; 44 t[now][j]=++tot; id[tot]=k; 45 now=tot; 46 pre=t[pre][j]; 47 } 48 } 49 inline int query(int l,int r,int x){ 50 int ans=0,now=rt[r]; 51 D(i,30,0){ 52 int j=((x>>i)&1)^1; 53 if (id[t[now][j]]>=l) ans|=1<<i; else j^=1; 54 now=t[now][j]; 55 } 56 return ans; 57 } 58 inline int getl(int x){ 59 it=s.find(x); 60 if (it--==s.begin()) return 0; 61 if (it--==s.begin()) return 0; 62 return *it; 63 } 64 inline int getr(int x){ 65 it=s.find(x); 66 if (++it==s.end()) return n+1; 67 if (++it==s.end()) return n+1; 68 return *it; 69 } 70 71 int main(){ 72 #ifndef ONLINE_JUDGE 73 freopen("3166.in","r",stdin); 74 freopen("3166.out","w",stdout); 75 #endif 76 n=getint(); 77 id[0]=-1; 78 Ins(rt[0],0,0); 79 F(i,1,n){ 80 a[i]=getint(); mx=max(mx,a[i]); 81 Ins(rt[i-1],a[i],i); 82 b[i].first=a[i]; 83 b[i].second=i; 84 } 85 sort(b+1,b+n+1); 86 D(i,n,1){ 87 s.insert(b[i].second); 88 l[b[i].second]=getl(b[i].second); 89 r[b[i].second]=getr(b[i].second); 90 } 91 int ans=0; 92 F(i,1,n) if (a[i]!=mx) 93 ans=max(ans,query(l[i]+1,r[i]-1,a[i])); 94 printf("%d\n",ans); 95 return 0; 96 }
3166: [Heoi2013]Alo
Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 524 Solved: 262
[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