[关键字]:splay hash 二分

[题目大意]:给出一个字符串,求出给定的两个后缀的的最长公共前缀。在求的过程中会有改变或在某个位置添加字符的操作。

//============================================================================================

[分析]:一听最长公共前缀马上想到后缀数组,但因为是动态维护所以后缀数组也无能为力。可以把字符串想象成一个数组,于是变成了动态插入和改变一个序列,还要能快速找到两个子区间——splay。求最长公共前缀可以用二分答案加验证的方法,二分长度先提取出这个区间然后判断这个区间的根节点的hash值(实际就是这棵子树的hash)是否和另一个相同。hash值得判断可以用进制法:hash=ord(s[1])*270+ord(s[2])*271+……+ord(s[n])*27n-1,在旋转时更新hash值为:hash[lc]+s[v]*27^(size[lc]+1)+hash[rc]*27^(size[lc]+2)。插入操作和一般splay插入无异修改只要修改掉这个点的值和hash值就行了。

[代码]:

View Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;const int MAXL=100015;
const int MOD=9875321;struct node
{node *c[2],*f;int dat,size,hash;
}*root,SC[MAXL],*null;
char s[MAXL];
int m,SS;
int d[MAXL];void Debug(node *v)
{if (v==null) return;Debug(v->c[0]);printf("%d ",v->dat);Debug(v->c[1]);
}node *New(int d,int h,node *fa)
{node *e=SC+ ++SS;e->size=1,e->f=fa;e->c[1]=e->c[0]=null;e->dat=d,e->hash=h;return e;
}void Update(node *v)
{if (v==null) return;v->size=v->c[0]->size+v->c[1]->size+1;v->hash=(long long)(v->c[0]->hash+(long long)v->dat*d[(v->c[0]->size+1)]+(long long)v->c[1]->hash*d[(v->c[0]->size+2)])%MOD;
}void Prepare()
{SS=-1;null=NULL;null=New(0,0,NULL);null->size=0;root=New(0,0,null);root->c[1]=New(0,0,root);d[1]=1;for (int i=2;i<=100010;++i)d[i]=(d[i-1]*27)%MOD;Update(root);
}void Rotate(node *x,int o)
{node *y=x->f;y->c[o]=x->c[!o];y->c[o]->f=y;x->f=y->f;if (y->f->c[0]==y)y->f->c[0]=x;elsey->f->c[1]=x;x->c[!o]=y;y->f=x;if (y==root) root=x;Update(y);
}void Splay(node *x,node *fa)
{while (x->f!=fa)if (x->f->f==fa)if (x->f->c[0]==x)Rotate(x,0);elseRotate(x,1);elseif (x->f->f->c[0]==x->f)if (x->f->c[0]==x)Rotate(x->f,0),Rotate(x,0);elseRotate(x,1),Rotate(x,0);else    if (x->f->c[1]==x)Rotate(x->f,1),Rotate(x,1);elseRotate(x,0),Rotate(x,1);Update(x);
}void Select(int k,node *fa)
{node *t=root;while (1){if (k==t->c[0]->size+1) break;if (k<t->c[0]->size+1) t=t->c[0];if (k>t->c[0]->size+1) k-=t->c[0]->size+1,t=t->c[1];}Splay(t,fa);
}int Hash(int x,int y)
{Select(x,null),Select(y+2,root);return root->c[1]->c[0]->hash;
}void Ask(int x,int y)
{int ans=0,n=root->size-2;for (int i=1<<18;i;i>>=1)if (x+i-1<=n && y+i-1<=n && Hash(x,x+i-1)==Hash(y,y+i-1))ans+=i,x+=i,y+=i;printf("%d\n",ans);
}void Ins(int x,char ch)
{Select(x+1,null),Select(x+2,root);root->c[1]->c[0]=New(ch-'a',ch-'a',root->c[1]);Splay(root->c[1]->c[0],null);//Debug(root),printf("\n");
}void Rep(int x,char ch)
{Select(x,null),Select(x+2,root);node *v=root->c[1]->c[0];v->dat=ch-'a';v->hash=(long long)(v->c[0]->hash+(long long)v->dat*d[(v->c[0]->size+1)]+(long long)v->c[1]->hash*d[(v->c[0]->size+2)])%MOD;//Debug(root),printf("\n");
}void Init()
{node *z,*t;Prepare();scanf("%s",s);int n=strlen(s);z=t=New(s[0]-'a',s[0]-'a',null);for (int i=1;i<n;++i)z=z->c[1]=New(s[i]-'a',s[i]-'a',z);root->c[1]->c[0]=t,t->f=root->c[1];Splay(z,null);//Debug(root),printf("\n");
}void Solve()
{char ch; int x,y;scanf("%d",&m),scanf("%c",&ch);for (int i=1;i<=m;++i){scanf("%c",&ch);if (ch=='Q') scanf("%d %d",&x,&y),Ask(x,y); elseif (ch=='I') scanf("%d %c",&x,&ch),Ins(x,ch); elsescanf("%d %c",&x,&ch),Rep(x,ch);scanf("%c",&ch);}
}int main()
{freopen("in","r",stdin);freopen("out","w",stdout);Init();Solve();return 0;
}

转载于:https://www.cnblogs.com/procedure2012/archive/2012/04/13/2445062.html

[JSOI2008 Prefix火星人]相关推荐

  1. 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解...

    题意不赘述了,太清晰了. 说题解:首先依据原字符串建立SPT.首尾建议多加一个空白字符. 给一个树构图,依照平衡树的前后大小顺序性质能够使它们始终维持为一个序列,而且能够通过rank找到序列的第k个. ...

  2. 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解

    题意不赘述了,太清晰了. 说题解:首先根据原字符串建立SPT,首尾建议多加一个空白字符. 给一个树构图,按照平衡树的前后大小顺序性质可以使它们始终维持为一个序列,并且可以通过rank找到序列的第k个. ...

  3. BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)

    描述 http://www.lydsy.com/JudgeOnline/problem.php?id=1014 给出一个字符串,有修改,插入,以及询问LCP(i,j)的操作. 分析 LCP在白书上面有 ...

  4. tkinter向文本框里加内容_给tkinter文本框添加右键菜单

    给tkinter文本框添加右键菜单 需求:直接右键点击使用tkinter创建的文本框是不会弹出菜单的.我们需要实现右键点击tkinter框架下的Entry对象.Text对象后弹出右键菜单可复制.粘贴和 ...

  5. 在html上绑定touch,实现html元素跟随touchmove事件的event.touches[0].clientX移动

    主要是使用了transform:translateX 实现 newWaterChart * { padding:0; margin:0; -webkit-box-sizing: border-box; ...

  6. 计算机丢失qntp.dll,ntp -q 输出说明

    -bash-3.00# ntpq -p remote           refid            st t when poll reach   delay   offset    disp ...

  7. struts2+spring3+hibernate4

    //web.xml<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi=" ...

  8. splay/fhq-treap 问卷调查反馈—— [JSOI2008]火星人prefix(splay),Strange Queries(fhq-treap)

    文章目录 [JSOI2008]火星人prefix Strange Queries [JSOI2008]火星人prefix BZOJ1014 思路很好想,哈希字符串即可 只是平衡树的码量大 注意因为sp ...

  9. BZOJ1014: [JSOI2008]火星人prefix

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

最新文章

  1. jquery技巧总结
  2. accp8.0html作业,Accp8.0HTML标签
  3. 学计算机方面该怎样保养眼睛,电脑工作者如何保护眼睛?吃什么对眼睛好
  4. 【Python】快速设置 pip 源
  5. C语言实现queue队列的算法(附完整源码)
  6. 计算机如何打开无线网络适配器,win7系统下网络适配器打不开怎么解决
  7. 在集合中根据条件来筛选数据
  8. Integer类的toBinaryString源码分析
  9. java opc 读取到数据块的数据_MES系统功能数据传输的介绍
  10. Java Android未捕获异常处理机制
  11. 神奇的中医!神奇的文化!
  12. 雨课堂知识点总结(七)
  13. HTTP缓存策略 304
  14. 接口测试如何生成随机的参数值
  15. 堪萨斯大学计算机硕士,美国堪萨斯大学计算机工程研究生申请要求
  16. 【小算法】求约数个数
  17. 使用R读取xls与xlsx文件
  18. Fedora修复grub2启动项grub rescue
  19. 转载:一位顶级黑客编写的最强反编译器
  20. css样式匹配苹果个型号手机

热门文章

  1. Gartner Magic Quadrant for Enterprise Network Firewall (2018,2017,2016,2015,2014,2013,2011,2010)
  2. Job 失败了怎么办?- 每天5分钟玩转 Docker 容器技术(133)
  3. C++等级考试知识点总结
  4. 街头抓拍之一:酷似福克纳的老头
  5. linux mint图标大小,Cinnamon:LinuxMint 15桌面设置小技巧
  6. source insight 函数不能跳到definition_小技能: Windows10突然不能复制粘贴谁搞鬼
  7. 三十二楼层选几层最好_买房楼层怎么选?建筑学家建议:一栋楼不管几层,最好避开这3层...
  8. python散点矩阵图_用python-pandas作图矩阵
  9. Unity3D之Shader自定义编辑器功能拓展
  10. 【caffe-Windows】微软官方caffe之 Python接口配置及图片生成实例