Jewel Magic UVA - 11996

这是一道用splay/非旋treap做的题(这里用的是非旋treap)

1/2/3是splay/非旋treap的常规操作。对于操作4,可以用哈希法求LCP。记hash(i,L)为子串[i,i+L-1](即第i个开始的L个)的hash值。记s[i]为序列第i位(编号从1开始),n为序列长度

如果通过某种方式做到能在O(logn)时间内取出一段子串的hash值,那么二分答案(即LCP长度x),可以在O(logn)时间内判一个x是否合法(如果hash(l,x)==hash(r,x)则认为[l,l+x-1]和[r,r+x-1]是相同的,合法,否则不合法),可以做到在O(log^2n)内完成一个操作4。当然,hash判字符串是否相同正确性可能受影响,因此可以多计算一些hash,当他们都相同时才认为字符串相同,可以将错误率降到足够小。

如何维护一段子串的hash值?首先定义x为任意整数,定义$hash(i,L)=s[i+L-1]*x^{L-1}+s[i+L-2]*x^{L-2}+...+s[i+1]*x+s[i]$

(这里及之后都省略了取模)

(简单记法:左边乘的次数小)

(另一种记法:另一种求法的伪代码表示:ans=0;for(j=i+L-1;j>=i;j--)  ans=ans*x+s[j];)

可以发现:如果已知hash(i,p)和hash(i+p,q)(即已知[i,i+p-1]和[i+p,i+p+q-1]的hash值),要求hash(i,p+q)(就是这两段合起来的hash值),那么:

令j=i+p,那么$hash(i,p+q)$

$=s[j+q-1]*x^{p+q-1}+s[j+q-2]*x^{p+q-2}+...+s[j]*x^p+s[i+p-1]*x^{p-1}+...+s[i]*x^0$

所以$hash(i,p+q)=hash(j,q)*x^p+hash(i,p)=hash(i,p)+hash(i+p,q)*x^p$

这样就得到了对于平衡树某个节点,根据子节点为根的子树的hash值与自身值求以自身为根的子树的hash值的方法(先将左子树和自身合起来,再将结果与右子树合起来)

当然,由于此题有一个翻转操作,对于一个节点要维护两个hash:正向序列hash和反向序列hash。翻转操作时顺便交换一下两个的值。

附:这道题没有卡hash,单hash就能过,

附:听说操作4有O(logn)的方法?待解决

错误记录:

1.141行误用build函数(build是用的左闭右闭区间),输入了(a+1,a+n+1)。(然而不知道为什么虽然过不了udebug的数据然而把题目A掉了)

2.没注意在字符前还是字符后插入

*3.posib函数写错:没有考虑要计算hash值的串超出长度范围的情况(就是第二个"&&"之前的部分)。错了不止一次

4.可能出现的错误:如果hash不用ull自然溢出,自己取模,那么要考虑爆int、爆longlong、负数等等

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. inline int rand1()
  5. {
  6. static int x=;
  7. return x=(48271LL*x+)%;
  8. }
  9. unsigned long long powx[];
  10. struct Node
  11. {
  12. Node(){}
  13. Node* ch[];
  14. int r;
  15. bool flip;
  16. int v;
  17. unsigned long long h,rh;
  18. int size;
  19. void upd()
  20. {
  21. if(ch[]) ch[]->pd();
  22. if(ch[]) ch[]->pd();
  23. size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
  24. h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
  25. rh=(ch[]?ch[]->rh:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->rh:)*powx[(ch[]?ch[]->size:)+];
  26. }
  27. void pd()
  28. {
  29. if(flip)
  30. {
  31. swap(ch[],ch[]);
  32. swap(h,rh);
  33. if(ch[]) (ch[]->flip)^=;
  34. if(ch[]) (ch[]->flip)^=;
  35. flip=;
  36. }
  37. }
  38. }nodes[];
  39. Node* root;int mem;
  40. Node* getnode(){return nodes+(mem++);}
  41. Node* merge(Node* a,Node* b)
  42. {
  43. if(a==NULL) return b;
  44. if(b==NULL) return a;
  45. if(a->r < b->r)
  46. {
  47. a->pd();a->ch[]=merge(a->ch[],b);a->upd();
  48. return a;
  49. }
  50. else
  51. {
  52. b->pd();b->ch[]=merge(a,b->ch[]);b->upd();
  53. return b;
  54. }
  55. }
  56. typedef pair<Node*,Node*> P;
  57. P split(Node* a,int n)
  58. {
  59. if(a==NULL) return P(NULL,NULL);
  60. P y;
  61. a->pd();int s=a->ch[] ? a->ch[]->size : ;
  62. if(s>=n)
  63. {
  64. y=split(a->ch[],n);
  65. a->ch[]=y.second;a->upd();
  66. y.second=a;
  67. }
  68. else
  69. {
  70. y=split(a->ch[],n-s-);
  71. a->ch[]=y.first;a->upd();
  72. y.first=a;
  73. }
  74. return y;
  75. }
  76. inline void insert(int k,int x)
  77. {
  78. Node* t=getnode();
  79. t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=x;t->flip=;t->upd();
  80. P y=split(root,k-);
  81. root=merge(merge(y.first,t),y.second);
  82. }
  83. inline void erase(int k)
  84. {
  85. P y=split(root,k-);
  86. P y2=split(y.second,);
  87. root=merge(y.first,y2.second);
  88. }
  89. inline void reverse(int l,int r)
  90. {
  91. if(l>r) swap(l,r);
  92. P y=split(root,l-);
  93. P y2=split(y.second,r-l+);
  94. y2.first->flip^=;
  95. root=merge(merge(y.first,y2.first),y2.second);
  96. }
  97. inline int size()
  98. {
  99. return root ? root->size : ;
  100. }
  101. inline unsigned long long geth(int l,int r)
  102. {
  103. if(l>r) return ;
  104. P y=split(root,l-);
  105. P y2=split(y.second,r-l+);
  106. unsigned long long ans=y2.first ? y2.first->h : ;
  107. root=merge(merge(y.first,y2.first),y2.second);
  108. return ans;
  109. }
  110. Node* build(int *l,int *r)
  111. {
  112. if(l>r) return NULL;
  113. if(l==r)
  114. {
  115. Node* t=getnode();
  116. t->ch[]=t->ch[]=NULL;t->r=rand1();t->v=*l;t->flip=;t->upd();
  117. return t;
  118. }
  119. else
  120. {
  121. int* mid=l+(r-l)/;
  122. return merge(build(l,mid),build(mid+,r));
  123. }
  124. }
  125. int n,m,q;
  126. int a[];
  127. const int X=;
  128. int l,r;
  129. inline bool posib(int x)
  130. {
  131. return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
  132. }
  133. int main()
  134. {
  135. register int i;
  136. int lx,rx,k,x,mid,tmp;
  137. powx[]=;
  138. for(i=;i<=;i++) powx[i]=powx[i-]*X;
  139. scanf("%d%d",&n,&q);
  140. for(i=;i<=n;i++) scanf("%1d",&a[i]);
  141. root=build(a+,a+n);
  142. while(q--)
  143. {
  144. scanf("%d",&tmp);
  145. if(tmp==)
  146. {
  147. scanf("%d%d",&k,&x);
  148. insert(k+,x);
  149. }
  150. else if(tmp==)
  151. {
  152. scanf("%d",&k);
  153. erase(k);
  154. }
  155. else if(tmp==)
  156. {
  157. scanf("%d%d",&l,&r);
  158. reverse(l,r);
  159. }
  160. else if(tmp==)
  161. {
  162. scanf("%d%d",&l,&r);
  163. lx=;rx=size()+;
  164. while(rx-lx>)
  165. {
  166. mid=(lx+rx)>>;
  167. if(posib(mid)) lx=mid;
  168. else rx=mid;
  169. }
  170. printf("%d\n",lx);
  171. }
  172. }
  173. return ;
  174. }

https://www.lydsy.com/JudgeOnline/problem.php?id=1014

https://www.luogu.org/problemnew/show/P4036

贴一下常数超大的代码

做法类似

  1. #pragma GCC optimize("Ofast")
  2. #include<cstdio>
  3. #include<algorithm>
  4. #include<cstring>
  5. using namespace std;
  6. inline int rand1()
  7. {
  8. static int x=;
  9. return x=(48271LL*x+)%;
  10. }
  11. unsigned long long powx[];
  12. struct Node
  13. {
  14. Node(){}
  15. Node* ch[];
  16. int r;
  17. int v;
  18. unsigned long long h;
  19. int size;
  20. void upd()
  21. {
  22. size=+(ch[]?ch[]->size:)+(ch[]?ch[]->size:);
  23. h=(ch[]?ch[]->h:)+v*powx[ch[]?ch[]->size:]+(ch[]?ch[]->h:)*powx[(ch[]?ch[]->size:)+];
  24. }
  25. }nodes[];
  26. Node* root;int mem;
  27. Node* getnode(){return nodes+(mem++);}
  28. Node* merge(Node* a,Node* b)
  29. {
  30. if(a==NULL) return b;
  31. if(b==NULL) return a;
  32. if(a->r < b->r)
  33. {
  34. a->ch[]=merge(a->ch[],b);a->upd();
  35. return a;
  36. }
  37. else
  38. {
  39. b->ch[]=merge(a,b->ch[]);b->upd();
  40. return b;
  41. }
  42. }
  43. typedef pair<Node*,Node*> P;
  44. P split(Node* a,int n)
  45. {
  46. if(a==NULL) return P(NULL,NULL);
  47. P y;
  48. int s=a->ch[] ? a->ch[]->size : ;
  49. if(s>=n)
  50. {
  51. y=split(a->ch[],n);
  52. a->ch[]=y.second;a->upd();
  53. y.second=a;
  54. }
  55. else
  56. {
  57. y=split(a->ch[],n-s-);
  58. a->ch[]=y.first;a->upd();
  59. y.first=a;
  60. }
  61. return y;
  62. }
  63. inline void insert(int k,int x)
  64. {
  65. Node* t=getnode();
  66. t->r=rand1();t->v=x;t->upd();
  67. P y=split(root,k-);
  68. root=merge(merge(y.first,t),y.second);
  69. }
  70. inline void erase(int k)
  71. {
  72. P y=split(root,k-);
  73. P y2=split(y.second,);
  74. root=merge(y.first,y2.second);
  75. }
  76.  
  77. inline int size()
  78. {
  79. return root ? root->size : ;
  80. }
  81. inline unsigned long long geth(int l,int r)
  82. {
  83. if(l>r) return ;
  84. P y=split(root,l-);
  85. P y2=split(y.second,r-l+);
  86. unsigned long long ans=y2.first ? y2.first->h : ;
  87. root=merge(merge(y.first,y2.first),y2.second);
  88. return ans;
  89. }
  90. Node* build(char *l,char *r)
  91. {
  92. if(l>r) return NULL;
  93. if(l==r)
  94. {
  95. Node* t=getnode();
  96. t->r=rand1();t->v=(int)(*l);t->upd();
  97. return t;
  98. }
  99. else
  100. {
  101. char* mid=l+(r-l)/;
  102. return merge(build(l,mid),build(mid+,r));
  103. }
  104. }
  105. int n,m,q;
  106. char a[];
  107. const int X=;
  108. int l,r;
  109. char tmp;
  110. inline bool posib(int x)
  111. {
  112. return (l+x-<=size())&&(r+x-<=size())&&(geth(l,l+x-)==geth(r,r+x-));
  113. }
  114. int main()
  115. {
  116. register int i;
  117. int lx,rx,k,mid;
  118. powx[]=;
  119. for(i=;i<=;i++) powx[i]=powx[i-]*X;
  120. scanf("%s",a+);n=strlen(a+);
  121. root=build(a+,a+n);
  122. scanf("%d",&q);
  123. while(q--)
  124. {
  125. tmp=getchar();while(tmp<'A'||tmp>'Z') tmp=getchar();
  126. if(tmp=='I')
  127. {
  128. scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
  129. insert(k+,(int)tmp);
  130. }
  131. else if(tmp=='R')
  132. {
  133. scanf("%d",&k);tmp=getchar();while(tmp<'a'||tmp>'z') tmp=getchar();
  134. erase(k);insert(k,(int)tmp);
  135. }
  136. else if(tmp=='Q')
  137. {
  138. scanf("%d%d",&l,&r);
  139. lx=;rx=size()+;
  140. while(rx-lx>)
  141. {
  142. mid=(lx+rx)>>;
  143. if(posib(mid)) lx=mid;
  144. else rx=mid;
  145. }
  146. printf("%d\n",lx);
  147. }
  148. }
  149. return ;
  150. }

Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix的更多相关文章

  1. [BZOJ1014][JSOI2008]火星人prefix

    [BZOJ1014][JSOI2008]火星人prefix 试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字 ...

  2. BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*

    BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...

  3. 2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)

    [JSOI2008]火星人prefix Time Limit: 10 Sec Memory Limit: 162 MB Submit: 8951 Solved: 2860 Description 火星 ...

  4. bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...

  5. [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  6. bzoj1014: [JSOI2008]火星人prefix splay+hash+二分

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  7. [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀. 比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 ...

  8. BZOJ1014[JSOI2008]火星人prefix(splay维护hash)

    Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...

  9. BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)

    题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...

随机推荐

  1. 火狐浏览器Firefox 如何下载网页的SWF视频,硅谷动力的网站视频怎么下载

    1 使用火狐浏览器查看到底视频在哪里,我随便开了一段视频,发现这个SWF(外框套了一个Control.swf,内层才是真实的09-class.swf)   2 我们从下面这一段代码中进行分析 < ...

  2. iOS开发--常用技巧 (MJRefresh详解)

         iOS开发--常用技巧 (MJRefresh详解) https://github.com/CoderMJLee/MJRefresh 下拉刷新01-默认 self.tableView.head ...

  3. Codeforces 768 E. Game of Stones 博弈DP

    E. Game of Stones   Sam has been teaching Jon the Game of Stones to sharpen his mind and help him de ...

  4. 解决手淘lib-flexible.js在移动端首次加载页面页面先放大后正常问题

    例如这样 然后这样 出现这样的原因一般是   静态的,即html里有一些静态的(即非js动态添加的) 如果在页面加载完成后,页面是用js动态添加的,这个问题就不太明显, doc.addEventLis ...

  5. easyUI下拉列表点击事件的使用

    可以通过input 和select来创建下拉列表 其中select的创建如下: 通过json来创建js数组 [{ "id":1, "text":"te ...

  6. YTU 2574: 空白格式化

    2574: 空白格式化 时间限制: 1 Sec  内存限制: 128 MB 提交: 233  解决: 118 题目描述 恭喜你进入了蓝桥杯总决赛,本次大赛采用了全自动机器测评系统. 如果你的答案与标准 ...

  7. [QT开发小结]LNK1104: cannot open file ‘gdi32.lib’ 解决方法

    1.环境变量 : Path = ;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin; 添加变量: INCLUDE = C:\Program ...

  8. 解决安装YII2 速度慢 失败等问题

    更改composer镜像地址为    composer config -g repo.packagist composer https://packagist.phpcomposer.com

  9. codeforces 686C C. Robbers' watch(dfs)

    题目链接: C. Robbers' watch time limit per test 2 seconds memory limit per test 256 megabytes input stan ...

  10. 使用Python操作Redis应用场景

    1. 安装pyredis 首先安装pip   1 2 3 4 5 6 7 8 <SHELL># apt-get install python-pip ...... <SHELL> ...