【BZOJ3166】Alo 可持久化trie树

首先我们枚举次大值,然后确定以这个数为次大值的最大区间。

这个区间就是左边第二个比它大的数的下标+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 }

时间: 2024-10-06 22:20:12

【BZOJ3166】Alo 可持久化trie树的相关文章

【bzoj3166】[Heoi2013]Alo 可持久化Trie树+STL-set

题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石有一个能量密度,记为ai,这些宝石的能量密度两两不同.现在你可以选取连续的一些宝石(必须多于一个)进行融合,设为  ai, ai+1, …, a j,则融合而成的宝石的能量密度为这些宝石中能量密度的次大值与其他任意一颗宝石的能量密度按位异或的值,即,设该段宝石能量密度次大值为k,则生成的宝石的能量密

BZOJ 3166 HEOI2013 Alo 可持久化Trie树

题目大意:给定一个不重复的序列a,在a中任选一个区间,求区间内的次大值与区间内的任意一个其它数的最大的异或值 首先我们枚举次大值 对于一个次大值 它可能选择的另一个数的取值范围为(l,r) 其中l为这个数左侧第二个比它大的数 r为这个数右侧第二个比它大的数 在这个区间内的Trie树中贪心寻找最大值即可 这个区间怎么求呢?我们维护一棵平衡树 将数从大到小将下标加进平衡树 每加进一个下标 比它大的数的下标都在平衡树中 求两次后继就是r 求两次前驱就是l 我偷懒写了set-- #include<set

[BZOJ3261&amp;BZOJ3166]可持久化trie树及其应用

可持久化trie树 可持久化trie树现在想来是比较好理解的了,但却看了一个下午... 相当于对于每个状态建立一条链(或者说一棵trie),求解的时候只要让两个点按照相同的步子走然后看sum的大小关系即可. tr[y].son[p xor 1]:=tr[x].son[p xor 1]; tr[y].sum:=tr[x].sum+1; 这两句要好好体会,对之后理解query过程中的语句很有帮助. if (tr[tr[x].son[p xor 1]].sum=tr[tr[x].son[p xor 1

bzoj4103异或运算 可持久化trie树

要去清华冬令营了,没找到2016年的题,就先坐一坐15年的. 因为n很小,就按照b串建可持久化trie树,a串暴力枚举. 其他的直接看代码. #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; inline int read() { int x=0,f=1,ch=getchar(); while(ch<'0'||ch

【bzoj4212】神牛的养成计划 Trie树+可持久化Trie树

题目描述 Hzwer成功培育出神牛细胞,可最终培育出的生物体却让他大失所望...... 后来,他从某同校女神 牛处知道,原来他培育的细胞发生了基因突变,原先决定神牛特征的基因序列都被破坏了,神牛hzwer很生气,但他知道基因突变的低频性,说不定还有以下优秀基因没有突变,那么他就可以用限制性核酸内切酶把它们切出来,然后再构建基因表达载体什么的,后面你懂的...... 黄学长现在知道了N个细胞的DNA序列,它们是若干个由小写字母组成的字符串.一个优秀的基因是两个字符串s1和s2,当且仅当s1是某序列

【bzoj3281】最大异或和 可持久化Trie树

题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操作,你需要找到一个位置 p,满足 l<=p<=r,使得:a[p] xor a[p+1] xor ... xor a[N] xor x 最大,输出最大是多少. 输入 第一行包含两个整数 N  ,M,含义如问题描述所示.   第二行包含 N个非负整数,表示初始的序列 A . 接下来 M行,每行描述一个

[bzoj3261]最大异或和[可持久化trie树]

因为要求异或和最大,所以可以考虑从高位开始,向低位枚举尽可能接近~x的值,所以以二进制位为关键字,建立可持久化trie树,根据异或和的性质,XOR_SUM{i,j}=XOR_SUM{1,j} xor XOR_SUM{1,i-1},所以查询问题也可以解决了. 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <c

BZOJ 2741【FOTILE模拟赛】L 分块+可持久化Trie树

题目大意 给出一个序列,求[l, r]中的最大连续xor 和. 强制在线 思路 先把整个序列分成n  √  块,预处理每一块的开头到每个数字的最大连续xor 和.这个我们只需处理出前缀xor 和,之后用可持久化Trie树就可以搞定.这样询问的右边就是整块的了.剩下左边的随便暴力一下就能过了.. CODE #define _CRT_SECURE_NO_WARNINGS #include <cmath> #include <cstdio> #include <cstring>

【BZOJ3689】异或之 堆+可持久化Trie树

[BZOJ3689]异或之 Description 给定n个非负整数A[1], A[2], ……, A[n].对于每对(i, j)满足1 <= i < j <= n,得到一个新的数A[i] xor A[j],这样共有n*(n-1)/2个新的数.求这些数(不包含A[i])中前k小的数.注:xor对应于pascal中的“xor”,C++中的“^”. Input 第一行2个正整数 n,k,如题所述.以下n行,每行一个非负整数表示A[i]. Output 共一行k个数,表示前k小的数. Samp