[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;
}

最新文章

  1. MyEclipse项目中的包按层次显示
  2. enmo_day_08
  3. 用C#表达式树优雅的计算24点
  4. A股市场各行业龙头股一览表
  5. UI学习笔记---第一天
  6. MyEclipse安装插件的几种方法 转
  7. win系统一键安装JDK和Tuxedo
  8. 期待已久的2012年度最佳jQuery插件揭晓
  9. Tcp 数据对象传输接口对象设计
  10. gulp+browser-sync使用方法
  11. NFC (Near Filed Communication)
  12. HTML&amp;CSS_基础03
  13. Macbook pro从购买服务器到搭建服务器环境(2)
  14. MySQL5.7参数log_timestamps
  15. Dijango学习_02_极简本地博客创建
  16. 第十六节:语法总结(3)(C#6.0和C#7.0新语法)
  17. Linux集群架构(一)
  18. JSX设置CSS样式详解
  19. 潭州课堂25班:Ph201805201 WEB 之 jQuery 第七课 (课堂笔记)
  20. Sql server bulk insert

热门文章

  1. Spring-boot+Mybatis+Maven+MySql搭建实例
  2. unity VideoPlayer
  3. while
  4. python数据分析笔记——数据加载与整理]
  5. form表单重置、清空方法记录
  6. k8s 问题
  7. Group by 内部排序
  8. moco入门
  9. keynote
  10. MATLAB安装libsvm无法使用解决办法(转)