「BZOJ3166」[HEOI2013] Alo
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
5
9 2 1 4 7
9 2 1 4 7
Sample Output
14
HINT
「样例解释」
选择区间[1,5],最大值为 7 xor 9。
对于 100%的数据有 1 ≤ n ≤ 50000, 0 ≤ ai ≤ 10^9
题解
按照权值的倒序,set维护位置,依次插入,则x的可行区间为[x前驱的前驱+1,x后继的后继-1](两半合起来)
用可持久化trie支持查询区间xor最大值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
#include<iostream> #include<cstdio> #include<cstring> #include<cstdlib> #include<set> #include<ctime> #include<vector> #include<queue> #include<algorithm> #include<map> #define N 50005 #define inf 1000000000 #define pa pair<int,int> #define ll long long using namespace std; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } set<int> q; int ans; int bin[35]; int n,root[N]; struct data{int val,pos;}a[N]; bool operator<(data a,data b) { return a.val>b.val; } struct trie{ int cnt; int ch[35*N][2],sum[35*N]; int insert(int x,int val){ int tmp,y;tmp=y=++cnt; for(int i=30;i>=0;i--) { int t=val&bin[i];t>>=i; ch[y][0]=ch[x][0];ch[y][1]=ch[x][1]; x=ch[x][t]; y=ch[y][t]=++cnt; sum[y]=sum[x]+1; } return tmp; } int query(int val,int l,int r){ int tmp=0; for(int i=30;i>=0;i--) { int t=val&bin[i];t>>=i; if(sum[ch[r][t^1]]-sum[ch[l][t^1]]) l=ch[l][t^1],r=ch[r][t^1],tmp+=bin[i]; else l=ch[l][t],r=ch[r][t]; } return tmp; } }trie; int main() { bin[0]=1;for(int i=1;i<=30;i++)bin[i]=bin[i-1]<<1; n=read(); for(int i=1;i<=n;i++) a[i].val=read(),a[i].pos=i; for(int i=1;i<=n;i++) root[i]=trie.insert(root[i-1],a[i].val); q.insert(-1);q.insert(inf);q.insert(-2);q.insert(inf+1); sort(a+1,a+n+1); q.insert(a[1].pos); for(int i=2;i<=n;i++) { int l=a[i].pos,r=a[i].pos,x=a[i].pos; set<int>::iterator t,p; p=q.lower_bound(x); t=p; r=*t;t++;r=*t-1; l=*--p;p--;l=*p+1; l=max(1,l);r=min(r,n); if(l!=r)ans=max(ans,trie.query(a[i].val,root[l-1],root[r])); q.insert(x); } printf("%d",ans); return 0; } |
滴滴滴QWQ我觉得可以不用set倒着插入,正着用双向链表不断删除就可以惹owo
莉莉好厉害QwQ,我只想到一个比set还麻烦的处理方法