可持久化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]].sum) then...

  刚开始曾经想过这个x已不一定在区间中,这样对吗?

  我们分情况讨论,如果上述语句值为真,考虑右边的y,y就算不是右边界但显然是因为>y中的链已经不能满足走到当前步了。

  再考虑左边界,如果一个在左边界以左的数都与后面的sum相等了,也就是[l,r]区间,以及其左边的一段都没有存在的链。

  这种情况显然是对的。

  如果不等呢?会因为左边界而导致原本应该不存在的链算入答案吗?

  如果存在一个在[l,r]以左的x以右的链,那当前走到的一定是这条链...因为从insert过程可以看出,我们的插入是按照下标的顺序的

  所以这种情况不存在,那不等的时候也是满足的。

  这样一来,对于可持久化trie树就完全理解了。但是应用的时候还是要注意一些东西。


BZOJ3261 

  Description

  给定一个非负整数序列 {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 最大,输出最大是多少。

 

  首先看到异或,还是可以比较自然地想到可持久化trie

  然后对于题目让我们求的这一串东西,可以想到前缀和。

  但由于异或运算的特殊性,设b[i]为1~i的异或和,b[i-1]^b[n]^x就是所求答案(∵ x^x=0)

  A操作就是普通的insert操作,对于Q,我们只需要执行一次query操作即可。

  在未学习可持久化trie之前这道题query的思维可圈可点 但是学习了以后再回头看就是一道简单的模板题了~

  1. program bzoj3261;
  2. const maxn=;
  3. var n,m,tot,tem,i,x,l,r:longint;
  4. ch:char;
  5. tr:array[-..maxn]of record sum:longint;son:array[..]of longint;end;
  6. root,a:array[-..maxn div ]of longint;
  7.  
  8. procedure insert(x:longint;var y:longint;ave,v:longint);
  9. var p:longint;
  10. begin
  11. inc(tot);y:=tot;
  12. tr[y].sum:=tr[x].sum+;
  13. if v< then exit;
  14. p:=(ave >> v) and ;
  15. tr[y].son[p xor ]:=tr[x].son[p xor ];
  16. insert(tr[x].son[p],tr[y].son[p],ave,v-);
  17. end;
  18.  
  19. function query(x,y,ave,v:longint):longint;
  20. var p:longint;
  21. begin
  22. if v< then exit();
  23. p:=(ave >> v) and ;
  24. if (tr[tr[x].son[p xor ]].sum=tr[tr[y].son[p xor ]].sum) then exit(query(tr[x].son[p],tr[y].son[p],ave,v-)) else
  25. exit(query(tr[x].son[p xor ],tr[y].son[p xor ],ave,v-)+ << v);
  26. end;
  27.  
  28. begin
  29. readln(n,m);
  30. tot:=;
  31. insert(root[-],root[],,);
      //这道题有个特殊之处在于0点也是要插入trie树的点
      //因此要小心越界
      //由于平时的习惯就是数组下标从-1开始,所以“好习惯能避免错误”^_^也是张老师说的
  32. tem:=;
  33. for i:= to n do
  34. begin
  35. read(a[i]);
  36. insert(root[i-],root[i],a[i] xor tem,);
  37. tem:=tem xor a[i];
  38. end;
  39. readln;
  40. for i:= to m do
  41. begin
  42. read(ch);
  43. if ch='A' then
  44. begin
  45. inc(n);readln(a[n]);
  46. insert(root[n-],root[n],a[n] xor tem,);
  47. tem:=tem xor a[n];
  48. end else
  49. begin
  50. readln(l,r,x);
  51. writeln(query(root[l-],root[r-],x xor tem,));
  52. end;
  53. end;
  54. end.

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}。 
现在你需要知道你怎么选取需要融合的宝石,才能使生成的宝石能量密度最大。

  首先这道题的解法是显而易见的...将每个数插入trie树中,然后我们最终答案所在的区间一定是极大区间

  然后可以枚举次大值,显然当这个数定下来的时候,它存在两个极大区间

  一个是它左边比它大的第二个数的下标+1~右边比它大的第一个数的下标-1

  一个是它左边比它大的第一个数的下标+1~右边比它大的第二个数的下标-1

  左右处理起来都一样~遇到的第一个数前几天正好做到过,用单调栈可以完美解决

  至于第二大...我写的比较长

  就是先按照值从大到小排序,然后用树状数组存以下标为下标的最大值和次大值,get的时候调的参数也是下标

  为什么可以这样呢..?因为当初学树状数组的时候我就用它求过最大值,当时老师也很惊奇我居然可以那么写

  但既然树状数组把1~i分成若干块,每一块都是到它前面一块的答案,那求最大值为何不可呢?

  然后今天又用它来保存两个值..一个最大一个次大...感觉非常爽啊...

  1. program bzoj3166;
  2. const maxn=;
  3. var tot,ans,i,n,x,y:longint;
  4. a,l,r,opt,root,id,l2,r2,aa:array[-..maxn div ]of longint;
  5. tar:array[-..maxn div ]of record x,y:longint;end;
  6. tr:array[-..maxn]of record sum:longint;son:array[..]of longint;end;
  7.  
  8. function max(a,b:longint):longint;
  9. begin
  10. if a>b then exit(a) else exit(b);
  11. end;
  12.  
  13. procedure swap(var x,y:longint);
  14. var tem:longint;
  15. begin
  16. tem:=x;x:=y;y:=tem;
  17. end;
  18.  
  19. procedure insert(x:longint;var y:longint;ave,v:longint);
  20. var p:longint;
  21. begin
  22. inc(tot);y:=tot;
  23. tr[y].sum:=tr[x].sum+;
  24. if v< then exit;
  25. p:=(ave >> v)and ;
  26. tr[y].son[p xor ]:=tr[x].son[p xor ];
  27. insert(tr[x].son[p],tr[y].son[p],ave,v-);
  28. end;
  29.  
  30. function query(x,y,ave,v:longint):longint;
  31. var p:longint;
  32. begin
  33. if v< then exit();
  34. p:=(ave >> v)and ;
  35. if tr[tr[y].son[p xor ]].sum=tr[tr[x].son[p xor ]].sum then exit(query(tr[x].son[p],tr[y].son[p],ave,v-)) else
  36. exit(query(tr[x].son[p xor ],tr[y].son[p xor ],ave,v-)+ << v);
  37. end;
  38.  
  39. procedure qsort(L,R:longint);
  40. var i,j,mid:longint;
  41. begin
  42. i:=L;j:=R;mid:=a[random(R-L+)+L];
  43. repeat
  44. while (i<R)and(a[i]>mid) do inc(i);
  45. while (L<j)and(a[j]<mid) do dec(j);
  46. if i<=j then
  47. begin
  48. swap(a[i],a[j]);swap(id[i],id[j]);
  49. inc(i);dec(j);
  50. end;
  51. until i>j;
  52. if i<R then qsort(i,R);
  53. if L<j then qsort(L,j);
  54. end;
  55.  
  56. procedure mend(x,y:longint);
  57. begin
  58. if y>tar[x].x then
  59. begin
  60. tar[x].y:=tar[x].x;
  61. tar[x].x:=y;
  62. end else
  63. if y>tar[x].y then tar[x].y:=y;
  64.  
  65. end;
  66.  
  67. procedure put(x,y:longint);
  68. begin
  69. if x= then
  70. begin
  71. mend(,y);
  72. exit;
  73. end;
  74. while x<=n+ do
  75. begin
  76. mend(x,y);
  77. x:=x+x and (-x);
  78. end;
  79. end;
  80.  
  81. function get(x:longint):longint;
  82. var ans1,ans2,tem:longint;
  83. begin
  84. ans1:=tar[].x;ans2:=tar[].y;
  85. tem:=x;
  86. while x<> do
  87. begin
  88. if tar[x].x>ans1 then
  89. begin
  90. ans2:=ans1;
  91. ans1:=tar[x].x;
  92. end else if tar[x].x>ans2 then ans2:=tar[x].x;
  93. if tar[x].y>ans1 then
  94. begin
  95. ans2:=ans1;
  96. ans1:=tar[x].y;
  97. end else if tar[x].y>ans2 then ans2:=tar[x].y;
  98. x:=x-x and (-x);
  99. end;
  100. exit(ans2);
  101. end;
  102.  
  103. procedure solve_lr;
  104. var i,tail:longint;
  105. begin
  106. a[]:=maxlongint;
  107. tail:=;opt[]:=;
  108. for i:= to n do
  109. begin
  110. while a[opt[tail]]<a[i] do dec(tail);
  111. l[i]:=opt[tail];
  112. inc(tail);opt[tail]:=i;
  113. end;
  114. a[n+]:=maxlongint;
  115. tail:=;opt[]:=n+;
  116. for i:=n downto do
  117. begin
  118. while a[opt[tail]]<a[i] do dec(tail);
  119. r[i]:=opt[tail];
  120. inc(tail);opt[tail]:=i;
  121. end;
  122. for i:= to n+ do id[i]:=i;
  123. qsort(,n+);
  124. fillchar(tar,sizeof(tar),);
  125. for i:= to n+ do
  126. begin
  127. l2[id[i]]:=get(id[i]);
  128. put(id[i],id[i]);
  129. end;
  130. fillchar(tar,sizeof(tar),);
  131. for i:= to n+ do
  132. begin
  133. r2[id[i]]:=n-get(n-id[i]+)+;
  134. put(n-id[i]+,n-id[i]+);
  135. end;
  136. end;
  137.  
  138. begin
  139. readln(n);
  140. for i:= to n do read(a[i]);
  141. aa:=a;
  142. solve_lr;
  143. a:=aa;
  144. tot:=;ans:=;
  145. for i:= to n do insert(root[i-],root[i],a[i],);
  146. for i:= to n do
  147. begin
  148. x:=l2[i]+;y:=r[i]-;
  149. ans:=max(ans,query(root[x-],root[y],a[i],));
  150. x:=l[i]+;y:=r2[i]-;
  151. ans:=max(ans,query(root[x-],root[y],a[i],));
  152. end;
  153. writeln(ans);
  154. end.

  感觉BZOJ对可持久化trie树特别偏爱,但是网上不像其他算法有大波的教程。

  其实我觉得这个算法真的很优美 在异或的类型题中尤其好用

  好好掌握 其实理解了之后根本不需要背

  大概数据结构题就是这样形象的吧

[BZOJ3261&BZOJ3166]可持久化trie树及其应用的更多相关文章

  1. 【BZOJ3166】[Heoi2013]Alo 可持久化Trie树+set

    [BZOJ3166][Heoi2013]Alo Description Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG , ...

  2. BZOJ3261: 最大异或和(可持久化trie树)

    题意 题目链接 Sol 设\(sum[i]\)表示\(1 - i\)的异或和 首先把每个询问的\(x \oplus sum[n]\)就变成了询问前缀最大值 可持久化Trie树维护前缀xor,建树的时候 ...

  3. 【bzoj3261】【最大异或和】可持久化trie树+贪心

    [pixiv] https://www.pixiv.net/member_illust.php?mode=medium&illust_id=61705397 Description 给定一个非 ...

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

    题目描述 Welcome to ALO ( Arithmetic and Logistic Online).这是一个VR MMORPG ,如名字所见,到处充满了数学的谜题.现在你拥有n颗宝石,每颗宝石 ...

  5. 【bzoj3261】最大异或和 可持久化Trie树

    题目描述 给定一个非负整数序列 {a},初始长度为 N.       有M个操作,有以下两种操作类型:1.A x:添加操作,表示在序列末尾添加一个数 x,序列的长度 N+1.2.Q l r x:询问操 ...

  6. BZOJ3261 最大异或和 解题报告(可持久化Trie树)

    本题链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3261 题目描述 给定一个非负整数序列{a},初始长度为N. 有M个操作,有以下两种操作类 ...

  7. 可持久化Trie树初步

    可持久化Trie树和可持久化线段树很像,依次插入信息,通过减法来进行历史版本查询. 2015年11月27日 bzoj3261 最大异或和 我们需要计算 a[p] xor a[p+1] xor ... ...

  8. [十二省联考2019]异或粽子——可持久化trie树+堆

    题目链接: [十二省联考2019]异或粽子 求前$k$大异或区间,可以发现$k$比较小,我们考虑找出每个区间. 为了快速得到一个区间的异或和,将原序列做前缀异或和. 对于每个点作为右端点时,我们维护出 ...

  9. BZOJ4477[Jsoi2015]字符串树——可持久化trie树

    题目描述 萌萌买了一颗字符串树的种子,春天种下去以后夏天就能长出一棵很大的字符串树.字符串树很奇特,树枝上都密密麻麻写满了字符串,看上去很复杂的样子.[问题描述]字符串树本质上还是一棵树,即N个节点N ...

随机推荐

  1. js数字格式化千分位格式

    带小数点的 var a = 8462948.2453; console.log(a.toLocaleString()) //8,462,948.245 不带小数点的 num.toString().re ...

  2. ASP NET Core --- 资源塑形, HATEOAS, Media Type

    参照 草根专栏- ASP.NET Core + Ng6 实战:https://v.qq.com/x/page/d07652pu1zi.html 一.Get返回资源塑形 1.添加集合塑形Enumerab ...

  3. LeetCode 389——找不同

    1. 题目 2. 解答 2.1. 方法一 将 s 和 t 转化为 Python 的列表,然后遍历列表 s 的元素,将它们从列表 t 中删除,最后列表 t 中会余下一个元素,即为所求. class So ...

  4. Spring Cloud 自定义ConfigServer 解决敏感信息存储问题

    公司需要将系统配置信息中的敏感信息独立存放. 现有系统采用Spring Cloud Config提供配置信息,其中敏感信息主要是Db配置,分解本次需求: (1)数据库配置信息分离(主要是Db信息). ...

  5. CCS Font 知识整理总结

    总是搞不懂 CCS 中如何正确的使用字体,这下明白了. 1.什么是 font-face font-face 顾名思义,就是文字的脸.字体是文字的外在形式,就是文字的风格,是文字的外衣.比如行书.楷书. ...

  6. BZOJ 4012 HNOI2015 开店 树的边分治+分治树

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4012 题意概述:给出一颗N点的树,保证树上所有点的度不超过3,树上每个点有权值,每条边有权 ...

  7. oracle或mysql定时增量更新索引数据到Elasticsearch

    利用kettle Spoon从oracle或mysql定时增量更新数据到Elasticsearch https://blog.csdn.net/jin110502116/article/details ...

  8. java高精度类尝试

    java高精度尝试, poj2109,比较坑的题目 import java.io.*; import java.util.*; import java.math.*; public class Mai ...

  9. 51nod 1680区间求和 (dp+树状数组/线段树)

    不妨考虑已知一个区间[l,r]的k=1.k=2....k=r-l+1这些数的答案ans(只是这一个区间,不包含子区间) 那么如果加入一个新的数字a[i](i = r+1) 则新区间[l, i]的答案为 ...

  10. 2017 湖南省赛 K Football Training Camp

    2017 湖南省赛 K Football Training Camp 题意: 在一次足球联合训练中一共有\(n\)支队伍相互进行了若干场比赛. 对于每场比赛,赢了的队伍得3分,输了的队伍不得分,如果为 ...