2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)
[JSOI2008]火星人prefix
Time Limit: 10 Sec Memory Limit: 162 MB
Submit: 8951 Solved: 2860
Description
火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。
Input
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操作有3种,如下所示1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字符串长度。3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字符串开头插入。限制:x不超过当前字符串长度
Output
对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
Sample Input
madamimadam
7
Q 1 7
Q 4 8
Q 10 11
R 3 a
Q 1 7
I 10 a
Q 2 11
Sample Output
5
1
0
2
1
HINT
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
对于第1,2个数据,字符串长度自始至终都不超过1,000
对于第3,4,5个数据,没有插入操作。
题意简述:维护一个字符串中任意两段后缀的最长前缀,支持修改和插入操作。
我们先来思考一下静态版本,如果让我们维护字符串中任意两段后缀的最长前缀,怎么做?后缀数组?
其实我们可以用更简单的二分+哈希的方法来替代,尽管二分+哈希的效率不如前者优秀,但是码量少,思维难度小,并且实际测试并不慢。
动态版本?
但当我们看到插入操作时,不难联想到这是一道平衡树的题目,怎么维护?
如果我们按每个字符在序列中的位置为序建立这棵平衡树来维护区间的哈希值的话,每次只需提取出(ql,n)(ql,n)(ql,n)和(qr,n)(qr,n)(qr,n)来二分答案即可。
代码如下
#include<bits/stdc++.h>
#define M 1000010
#define bas 37
using namespace std;
typedef pair<int,int> res;
unsigned int hash[M],po[M];
int q,son[M][2],siz[M],v[M],rd[M],tot=0,root=0;
inline void pushup(int p){
siz[p]=siz[son[p][0]]+siz[son[p][1]]+1;
hash[p]=hash[son[p][0]]+v[p]*po[siz[son[p][0]]]+hash[son[p][1]]*po[siz[son[p][0]]+1];
}
inline int merge(int a,int b){
if(!a||!b)return a+b;
if(rd[a]<rd[b]){son[a][1]=merge(son[a][1],b),pushup(a);return a;}
son[b][0]=merge(a,son[b][0]),pushup(b);return b;
}
inline res split(int a,int k){
if(!a)return res(0,0);
res ans,tmp;
if(siz[son[a][0]]>=k){
tmp=split(son[a][0],k);
son[a][0]=tmp.second,pushup(a);
ans.first=tmp.first,ans.second=a;
return ans;
}
tmp=split(son[a][1],k-siz[son[a][0]]-1);
son[a][1]=tmp.first,pushup(a);
ans.first=a,ans.second=tmp.second;
return ans;
}
inline int build(int val){
int ret=++tot;
hash[tot]=v[tot]=val;
son[tot][0]=son[tot][1]=0;
rd[tot]=rand();
siz[tot]=1;
return tot;
}
inline void insert(int pos,int v){
res tmp=split(root,pos);
int p=build(v);
root=merge(merge(tmp.first,p),tmp.second);
}
inline void erase(int pos){
res x=split(root,pos);
res y=split(x.first,pos-1);
root=merge(y.first,x.second);
}
char s[150005];
inline int ask(int p,int len){
if(p+len-1>siz[root])return -1;
res x=split(root,p-1);
res y=split(x.second,len);
int ret=hash[y.first];
root=merge(x.first,merge(y.first,y.second));
return ret;
}
inline void query(int ql,int qr){
int l=0,r=siz[root]-qr+1,ans=0;
while(l<=r){
int mid=l+r>>1;
int ax=ask(ql,mid),ay=ask(qr,mid);
if(ax==-1||ay==-1){r=mid-1;continue;}
if(ax==ay)ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
int main(){
po[0]=1;
for(int i=1;i<=100000;++i)po[i]=po[i-1]*bas;
scanf("%s",s+1);
int len=strlen(s+1),l,r;
for(int i=1;i<=len;++i)root=merge(root,build(s[i]-'a'));
scanf("%d",&q);
while(q--){
char op[3],c[3];
scanf("%s",op);
if(op[0]=='Q'){
scanf("%d%d",&l,&r);
query(l,r);
}
if(op[0]=='R'){
scanf("%d%s",&l,c);
erase(l);
insert(l-1,c[0]-'a');
}
if(op[0]=='I'){
scanf("%d%s",&l,&c);
insert(l,c[0]-'a');
}
}
return 0;
}
2018.06.28 BZOJ1014 [JSOI2008]火星人prefix(非旋treap+hash)的更多相关文章
- [Bzoj1014][JSOI2008]火星人prefix(无旋Treap&hash)
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 因为涉及到增加和修改,所以后缀数组就被pass掉了,想到的就是平衡树维护hash值 ...
- BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*
BZOJ1014 JSOI2008 火星人prefix Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符 ...
- [BZOJ1014][JSOI2008]火星人prefix
[BZOJ1014][JSOI2008]火星人prefix 试题描述 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字 ...
- bzoj千题计划106:bzoj1014 [JSOI2008]火星人prefix
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 两个后缀的最长公共前缀:二分+hash 带修改带插入:splay维护 #include< ...
- Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix
Jewel Magic UVA - 11996 这是一道用splay/非旋treap做的题(这里用的是非旋treap) 1/2/3是splay/非旋treap的常规操作.对于操作4,可以用哈希法求LC ...
- 2018.08.06 bzoj1500: [NOI2005]维修数列(非旋treap)
传送门 平衡树好题. 我仍然是用的fhqtreap,感觉速度还行. 维护也比线段树splay什么的写起来简单. %%%非旋treap大法好. 代码: #include<bits/stdc++.h ...
- [bzoj1014][JSOI2008]火星人prefix_非旋转Treap_hash_二分
火星人prefix bzoj-1014 JSOI-2004 题目大意:给定一个字符串,支持三种操作:1.查询:两个后缀之间的$LCP$:2.单点修改:3.插入一个字符. 注释:$1\le n\le 1 ...
- [BZOJ1014] [JSOI2008] 火星人prefix (splay & 二分答案)
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- bzoj1014: [JSOI2008]火星人prefix splay+hash+二分
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
随机推荐
- C# EF 基础操作
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Devexpress 百分号显示格式
百分号:{0:P}表示显示为百分号模式.如数据源中为0.5.表示出来为50%
- 2.vo传参模式和ModerDriven传参模式
转自:https://wenku.baidu.com/view/84fa86ae360cba1aa911da02.html Copy上面的myStruts2项目,改名为myStruts2Vo项目.作如 ...
- nginx直接返回json
尝试配置nginx.conf之后,访问直接变成下载文件... 查阅之后,发现需要配置返回内容的格式. location ~ ^/get_json { default_type application/ ...
- UI5-文档-4.19-Reuse Dialogs
在此步骤中,我们将扩展重用概念,并在组件级别调用对话框. 在步骤16中,我们创建了一个对话框作为片段,以使其可跨视图或跨整个应用程序重用.但是我们将检索对话框实例和分别打开和关闭对话框实例的逻辑放置在 ...
- UI5-文档-2-开发环境
这一部分将指导您安装.配置和设置SAPUI5开发环境的最常见和推荐用例. 请注意:您可以在不同的平台上使用SAPUI5.各自平台的许可和维护条件也适用于SAPUI5.例如,如果在SAP云平台上使用SA ...
- visibility和display
visibility: hidden----将元素隐藏,但是在网页中该占的位置还是占着.display: none----将元素的显示设为无,即在网页中不占任何的位置.
- ArcGIS案例学习笔记1_1
ArcGIS案例学习笔记1_1 联系方式:谢老师,135_4855_4328, xiexiaokui#qq.com 时间:第一天上午 准备 0.U盘复制ArcGIS培训*** 1.练习数据不要放到桌面 ...
- hivepython 实现一行转多行
案例1: ==效果等同于一行转多行 数据表名称:zhangb.gid_tags 数据格式,每行是2个字段,(gid,tags) ,可能有脏数据,分隔符为“\t”, ANDROID-9de77225 ...
- 2021工厂增加2322仓位需求,参与FP分析
在以下语句取消2322工厂即可 INSERT INTO STG.SAP_MARD(MATNR, WERKS, LGORT, LABST, UMLME, INSME, EINME, SPEME, LGO ...