标签:
首先我们枚举次大值,然后确定以这个数为次大值的最大区间。
这个区间就是左边第二个比它大的数的下标+1,右边第二个比它大的数的下标-1。
难就难在找到这个区间。
我们考虑将数排序,然后从大到小将数原来的下标插入set,此时set里的值都大于等于当前插入的数。
所以利用set找到前驱的前驱,后继的后继,就是我们需要的区间。
找到区间后,剩下的就是对于一个给定的数,在一段区间里找到一个数使其异或值最大,直接用可持久化trie就可以了。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <algorithm> 6 #include <set> 7 8 using namespace std; 9 10 const int N = 100000 + 5; 11 const int len = 30; 12 13 namespace Trie{ 14 int tot, root[N]; 15 int son[N*50][2], cnt[N*50]; 16 void insert( int y, int &x, int num, int d ){ 17 cnt[x = ++tot] = cnt[y]+1; 18 if ( d < 0 ) return; 19 int p = (num>>d)&1; 20 son[x][p^1] = son[y][p^1]; 21 insert(son[y][p],son[x][p],num,d-1); 22 } 23 int query( int x, int y, int num, int d ){ 24 if ( d < 0 ) return 0; 25 int p = (num>>d)&1; 26 int k = cnt[son[y][p^1]]-cnt[son[x][p^1]]; 27 if ( k ) return query(son[x][p^1],son[y][p^1],num,d-1)+(1<<d); 28 else return query(son[x][p],son[y][p],num,d-1); 29 } 30 } 31 32 using namespace Trie; 33 34 int n, ans, w[N], k[N]; 35 36 set <int> s; 37 set <int> ::iterator it; 38 39 bool cmp( const int &A, const int &B ){ 40 return w[A] > w[B]; 41 } 42 43 int Getl( int x ){ 44 it = s.find(x); 45 if ( it-- == s.begin() ) return 0; 46 if ( it-- == s.begin() ) return 0; 47 return *it; 48 } 49 int Getr( int x ){ 50 it = s.find(x); 51 if ( ++it == s.end() ) return n+1; 52 if ( ++it == s.end() ) return n+1; 53 return *it; 54 } 55 56 int main(){ 57 scanf( "%d", &n ); 58 for ( int i = 1; i <= n; i ++ ) scanf( "%d", &w[i] ); 59 for ( int i = 1; i <= n; i ++ ) k[i] = i; 60 sort( k + 1 , k + 1 + n , cmp ); 61 for ( int i = 1; i <= n; i ++ ) 62 insert(root[i-1],root[i],w[i],len); 63 s.insert(k[1]); 64 for ( int i = 2; i <= n; i ++ ){ 65 s.insert(k[i]); 66 int l = Getl(k[i]); 67 int r = Getr(k[i]); 68 int x = w[k[i]]; 69 int temp = query(root[l],root[r-1],x,len); 70 ans = max( ans,temp ); 71 } 72 printf( "%d\n", ans ); 73 74 return 0; 75 }
标签:
原文地址:http://www.cnblogs.com/Vonnie/p/5224330.html