[bzoj3166][HEOI2013]ALO
来源:互联网 发布:淘宝口令是什么意思啊 编辑:程序博客网 时间:2024/06/14 15:21
题目大意
现有一个序列,一段长度>1区间的权值为区间内的次大值与区间内除次大值外的数的异或最大值。
例如:9 2 1 4 7
次大值为7,7 xor 9=14最大。
保证序列内元素两两不同。N<=50000,每个元素都不超过10^9.
解决次大值
我们考虑枚举一个数作为次大值,然后求出其最大往左和最大往右,那么显然,需要在这个区间内寻找与其异或最大的数。注意序列内的最大值永远不可能作为次大值。
我们考虑从大到小排序,顺次插入线段树中。对于现在要插入的原来在第i位的元素,j为在1~i-1区间中最右元素所在位置,k为在1~j-1区间中最右元素所在位置。显然k+1~i这个区间的次大值为i。往右扩展情况类似。因此我们可以用n log n的时间处理出扩展情况。
异或最大值
为了方便,我们可以把一个元素的扩展情况分成两块,一块是往左扩展情况,另一块是往右扩展情况。
对于往左扩展情况,从左到右做。当前做到i,其往左最大扩展到j。那么我们需要在j+1~i-1中寻找最大异或数。我们可以想到贪心,因为所有元素不超过10^9,所以化为二进制最多30位,将前i-1个元素放入trie中,每次尽量走能使当前位异或后为1的那一侧,即可。
但注意我们需满足元素位置号>j,因此在trie中每个结点维护一个最大标号。只要最大标号>j,则这条路一定可以走下去。
再类似的倒过来做一遍。
参考程序
#include<cstdio>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;struct dong{ int x,id;};const int maxn=50000+10,ws=30;int tree[maxn*33][2],g[maxn*33],num[maxn*5],sum[maxn*5];int a[maxn][33],b[maxn],s[maxn],ans[maxn],pre[maxn],suf[maxn];dong c[maxn];int i,j,k,l,r,t,n,m,tot,top;void insert(int p,int t,int i){ g[p]=i; if (t<0) return; if (!tree[p][a[i][t]]) tree[p][a[i][t]]=++tot; insert(tree[p][a[i][t]],t-1,i);}int find(int p,int t,int i,int j,int flag){ if (t<0) return 0; if (!flag){ if (tree[p][1-a[i][t]]&&g[tree[p][1-a[i][t]]]>j) return find(tree[p][1-a[i][t]],t-1,i,j,flag)+(1<<t)*(1-a[i][t]); else return find(tree[p][a[i][t]],t-1,i,j,flag)+(1<<t)*a[i][t]; } else{ if (tree[p][1-a[i][t]]&&g[tree[p][1-a[i][t]]]<j) return find(tree[p][1-a[i][t]],t-1,i,j,flag)+(1<<t)*(1-a[i][t]); else return find(tree[p][a[i][t]],t-1,i,j,flag)+(1<<t)*a[i][t]; }}bool cmp(dong a,dong b){ return a.x>b.x;}void change(int p,int l,int r,int a){ if (l==r){ sum[p]=num[p]=l; return; } int mid=(l+r)/2; if (a<=mid) change(p*2,l,mid,a);else change(p*2+1,mid+1,r,a); num[p]=max(num[p*2],num[p*2+1]); sum[p]=min(sum[p*2],sum[p*2+1]);}int get(int p,int l,int r,int a,int b,int flag){ if (l==a&&r==b){ if (flag) return num[p];else return sum[p]; } int mid=(l+r)/2; if (b<=mid) return get(p*2,l,mid,a,b,flag); else if (a>mid) return get(p*2+1,mid+1,r,a,b,flag); else{ int j=get(p*2,l,mid,a,mid,flag),k=get(p*2+1,mid+1,r,mid+1,b,flag); if (flag) return max(j,k);else return min(j,k); }}int main(){ scanf("%d",&n); fo(i,1,n){ j=0; scanf("%d",&t); b[i]=t; while (t){ a[i][j]=t%2; t/=2; j++; } c[i].x=b[i];c[i].id=i; } sort(c+1,c+n+1,cmp); fo(i,1,4*n) sum[i]=n+1; fo(i,1,n){ j=get(1,1,n,1,c[i].id,1); if (!j) pre[c[i].id]=0; else{ if (j>1){ k=get(1,1,n,1,j-1,1); j=k+1; } pre[c[i].id]=j; } j=get(1,1,n,c[i].id,n,0); if (j==n+1) suf[c[i].id]=n+1; else{ if (j<n){ k=get(1,1,n,j+1,n,0); j=k-1; } suf[c[i].id]=j; } change(1,1,n,c[i].id); } fo(i,1,n){ k=find(0,ws,i,pre[i]-1,0); ans[i]=b[i]^k; insert(0,ws,i); } fo(i,0,tot) g[i]=n+1,tree[i][0]=tree[i][1]=0; fd(i,n,1){ k=find(0,ws,i,suf[i]+1,1); ans[i]=max(ans[i],b[i]^k); insert(0,ws,i); } m=0; l=r=0; fo(i,1,n){ if (pre[i]==0&&suf[i]==n+1) ans[i]=0; if (ans[i]>m){ m=ans[i]; l=pre[i];r=suf[i]; } } printf("%d\n",m); return 0;}
0 0
- bzoj3166: [Heoi2013]Alo
- [bzoj3166][HEOI2013]ALO
- bzoj3166: [Heoi2013]Alo
- BZOJ3166: [Heoi2013]Alo
- BZOJ3166 [Heoi2013]Alo 可持久化Trie
- 【bzoj3166】【HEOI2013】【Alo】【set+可持久化trie】
- [BZOJ3166][Heoi2013]Alo(可持久化线段树+可持久化tire树)
- bzoj 3166: [Heoi2013]Alo
- 3166: [Heoi2013]Alo
- BZOJ 3166 [Heoi2013]Alo
- 【ChairTrie】【bzoj 3166】: [Heoi2013]Alo
- [GDOI模拟2015.12.19][HEOI2013]ALO
- 3166: [Heoi2013]Alo 可持久化trie
- 可持久化01Trie [Heoi2013]Alo
- bzoj 3166: [Heoi2013]Alo 可持久化trie
- BZOJ 3166 HEOI2013 Alo 可持久化Trie树
- 【BZOJ】【P3166】【Heoi2013】【Alo】【题解】【可持久化Trie+set】
- BZOJ 3166: [Heoi2013]Alo|可持久化Trie树
- DBUtils 使用示例
- Swift Tutorial: Repeating Steps with Loops
- 技术路线的选择重要但不具有决定性
- Linq to sql
- [转]在Eclipse中使用JUnit4进行单元测试(初级篇)
- [bzoj3166][HEOI2013]ALO
- 关于HTML发送AJAX请求一直重复刷新页面问题
- 前端工程师与SEO搜索引擎优化(笔记总结)
- 腾讯公布虚拟现实头显方案、SDK以及开发者计划
- 如何使用Golang来处理支付宝的回调
- Learning Python(6)--Python的命令行解析argparse模块
- 39节课后3解
- web开发基础1
- ❀自我唠嗑OC-数组类,字典类,集合类