BZOJ1014 JSOI2008 火星人prefix


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个数据,没有插入操作。


我们发现有修改和添加字符的操作,就想到了平衡树

又因为我比较喜欢非旋转Treap

然后就写了一波

注意这里的Treap不能按照字符的大小来建树,我们应该根据字符串中字符的先后顺序来建树,添加字符就直接在第k个位置后面添加就好了,修改比较常规,直接先分裂再合并就行了

现在我们考虑怎么求字符串的两个后缀的最长公共前缀,首先如果没有修改和添加操作我们肯定会选择后缀数组,但现在我们有了修改和添加操作,所以我们需要换一种方式思考。在一般情况下,字符串的hash值是否相同可以判断字符串是否相同,所以我们可以用hash,但是如果这样暴力判断,时间效率依旧不优秀,达到O(n2logn)" role="presentation">O(n2logn)O(n2logn),那么我们可以发现这个hash段的长度是具有二分性的,所以我们就可以用二分来查询,就可以将时间优化成O(nlog2n)" role="presentation">O(nlog2n)O(nlog2n)

那么我们怎么维护hash呢,首先,在Treap上进行向上更新操作的时候可以通过合并左右区间hash值来维护,那么我们就需要与处理base偏移量(pow数组),然后通过

hash[t]=hash[ls[t]]+pow[siz[ls[t]]]∗val[t]+pow[siz[ls[t]]+1]∗hash[rs[t]]" role="presentation">hash[t]=hash[ls[t]]+pow[siz[ls[t]]]∗val[t]+pow[siz[ls[t]]+1]∗hash[rs[t]]hash[t]=hash[ls[t]]+pow[siz[ls[t]]]∗val[t]+pow[siz[ls[t]]+1]∗hash[rs[t]]

来计算当前节点为根的子树hash值,其中val是当前节点所代表的字符的编号(字符-‘a’+1)

然后我们在二分的时候直接剥离出从x、y开始长度为len的子树就好了


#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define Base 37
typedef pair<int,int> pi;
struct Treap{
int tot,root,n;
int siz[N],key[N],ls[N],rs[N],val[N];
unsigned int hash[N],pow[N];
void init(){
tot=root=0;
pow[0]=1;
for(int i=1;i<=N;i++)
pow[i]=pow[i-1]*Base;
}
int new_treap_point(int vl){
int newt=++tot;
siz[newt]=1;
hash[newt]=val[newt]=vl;
key[newt]=rand();
ls[newt]=rs[newt]=0;
return newt;
}
void update(int t){
siz[t]=siz[ls[t]]+siz[rs[t]]+1;
hash[t]=hash[ls[t]]+pow[siz[ls[t]]]*val[t]+pow[siz[ls[t]]+1]*hash[rs[t]];
}
int merge(int a,int b){
if(!a)return b;
if(!b)return a;
if(key[a]<key[b]){
rs[a]=merge(rs[a],b);
update(a);return a;
}else{
ls[b]=merge(a,ls[b]);
update(b);return b;
}
}
pi split(int t,int k){
if(!t)return pi(0,0);
pi ans;
if(siz[ls[t]]>=k){
pi tmp=split(ls[t],k);
ls[t]=tmp.second;
update(t);
ans.first=tmp.first;
ans.second=t;
}else{
pi tmp=split(rs[t],k-siz[ls[t]]-1);
rs[t]=tmp.first;
update(t);
ans.first=t;
ans.second=tmp.second;
}
return ans;
}
void insert(int k,int vl){
pi x=split(root,k);
int t=new_treap_point(vl);
root=merge(merge(x.first,t),x.second);
}
void erase(int k){
pi x=split(root,k);
root=merge(split(x.first,k-1).first,x.second);
}
void modify(int k,int vl){
erase(k);
insert(k-1,vl);
}
int queryhash(int t,int len){
if(t+len-1>siz[root])return -1;
pi x=split(root,t-1);
pi y=split(x.second,len);
int ans=hash[y.first];
root=merge(x.first,merge(y.first,y.second));
return ans;
}
int query(int x,int y){
int l=0,r=N,ans=0;
while(l<=r){
int mid=(l+r)>>1;
int px=queryhash(x,mid),py=queryhash(y,mid);
if(px==-1||py==-1){r=mid-1;continue;}
if(px==py)ans=mid,l=mid+1;
else r=mid-1;
}
return ans;
}
}treap;
int n,m;
char s[N],c[5];
int main(){
srand(time(0));
treap.init();
scanf("%s",s+1);
n=strlen(s+1);
treap.n=n;
for(int i=1;i<=n;i++)
treap.root=treap.merge(treap.root,treap.new_treap_point(s[i]-'a'+1));
scanf("%d",&m);
while(m--){
scanf("%s",c);
if(c[0]=='Q'){
int x,y;scanf("%d%d",&x,&y);
printf("%d\n",treap.query(x,y));
}else if(c[0]=='I'){
int x;scanf("%d%s",&x,c);
treap.insert(x,c[0]-'a'+1);
}else{
int x;scanf("%d%s",&x,c);
treap.modify(x,c[0]-'a'+1);
}
}
return 0;
}

BZOJ1014 JSOI2008 火星人prefix 【非旋转Treap】*的更多相关文章

  1. [bzoj1014][JSOI2008]火星人prefix_非旋转Treap_hash_二分

    火星人prefix bzoj-1014 JSOI-2004 题目大意:给定一个字符串,支持三种操作:1.查询:两个后缀之间的$LCP$:2.单点修改:3.插入一个字符. 注释:$1\le n\le 1 ...

  2. [Bzoj1014][JSOI2008]火星人prefix(无旋Treap&hash)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1014 因为涉及到增加和修改,所以后缀数组就被pass掉了,想到的就是平衡树维护hash值 ...

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

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

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

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

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

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

  6. Jewel Magic UVA - 11996 || bzoj1014: [JSOI2008]火星人prefix

    Jewel Magic UVA - 11996 这是一道用splay/非旋treap做的题(这里用的是非旋treap) 1/2/3是splay/非旋treap的常规操作.对于操作4,可以用哈希法求LC ...

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

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

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

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

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

    题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符. 前几天刚学了hash+二分求lcp,就看到这题. 原来splay还能这么用?!原来splay模板这么好写?我以前写的s ...

随机推荐

  1. 深度学习中 Batch Normalization为什么效果好

    看mnist数据集上其他人的CNN模型时了解到了Batch Normalization 这种操作.效果还不错,至少对于训练速度提升了很多. batch normalization的做法是把数据转换为0 ...

  2. key中断

    1 中断,很短的时间过去,然后回来.2 信号,软中断,而中断属于硬中断.3 实时内核,和分时内核.4 同步,预先知道发生,异步,预先不知道要发生,中断属于异步.5 arm一次执行一个中断.6 irq中 ...

  3. SpringBoot+MyBatis简单数据访问应用

    因为实习用的是MyBatis框架,所以写一篇关于SpringBoot整合MyBatis框架的总结. 一,Pom文件 <?xml version="1.0" encoding= ...

  4. nyoj115——裸dijksta(点之间最短路)

    城市平乱 时间限制:1000 ms  |  内存限制:65535 KB 难度:4   描述 南将军统领着N个部队,这N个部队分别驻扎在N个不同的城市. 他在用这N个部队维护着M个城市的治安,这M个城市 ...

  5. BZOJ 1010 [HNOI2008]玩具装箱 (斜率优化DP)

    题目链接 http://www.lydsy.com/JudgeOnline/problem.php?id=1010 思路 [斜率优化DP] 我们知道,有些DP方程可以转化成DP[i]=f[j]+x[i ...

  6. ADO.NET简介

    一.ADO.NET ADO.NET源起ADO(ActiveX Data Objects),是一个COM组件库,在NET编程环境中优先使用的数据访问接口, 提供对诸如 SQL Server 和 XML ...

  7. T4模板的基本结构

    (转自:http://www.cnblogs.com/yank/archive/2012/02/14/2342287.html) T4模板的基本结构 代码块的总体分类,就是两种:文本.程序脚本. 我感 ...

  8. Docker的大坑小洼(二)

    再谈<Docker的大坑小洼> 今天闲暇看了一下宏亮同学写的一篇<Docker的大坑小洼>,非常受启发.因为Docker的文章真的很多了,但大家如果只是玩一玩,有很多坑是不会碰 ...

  9. java与mysql时间类型对应的问题

    项目中遇到一个问题,从后台给出的json字符串中取得的时间,之后通过方法转换成  yyyy-MM-dd hh:mm:ss 的时候,转换后的得到的竟然是1969年...之后排查问题: 发现了在mayba ...

  10. idea 配置springmvc+mybatis(图文教程)

    idea配置 spirngmvc+maven+mybatis 数据库采用的是mysql  服务器容器用的是tomcat8 废话不多说直接干! 首先新建一个 maven工程, "File&qu ...