[BZOJ1014][JSOI2008]火星人prefix

bzoj
luogu

题意

给你一个串,支持三种操作:
1、在一个位置插入一个字符。
2、把一个位置的字符修改。
3、查询两个后缀的\(lcp\)
任意时候字符串长度\(\le 10^5\),询问操作\(\le 10^4\),总操作数\(\le 1.5*10^5\)

sol

二分+\(hash\)。只要在\(splay\)上维护一个区间的\(hash\)值就可以了。
每次二分一个长度后直接把两个\(lcp\)对应的区间区间\(split\)出来然后判断。复杂度两个\(\log\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define ull unsigned long long
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 1e5+5;
const int base = 1705;
int n,m,fa[N],ch[2][N],key[N],sz[N],root;ull pw[N],hash[N];
char s[N];
bool son(int x){return x==ch[1][fa[x]];}
void pushup(int x)
{
	hash[x]=hash[ch[0][x]]*pw[sz[ch[1][x]]+1]+key[x]*pw[sz[ch[1][x]]]+hash[ch[1][x]];
	sz[x]=sz[ch[0][x]]+sz[ch[1][x]]+1;
}
void rotate(int x)
{
	int y=fa[x],z=fa[y],c=son(x);
	ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y;
	fa[x]=z;if (z) ch[son(y)][z]=x;
	ch[c^1][x]=y;fa[y]=x;pushup(y);
}
void splay(int x,int goal)
{
	for (int y=fa[x];y!=goal;rotate(x),y=fa[x])
		if (fa[y]!=goal) son(x)^son(y)?rotate(x):rotate(y);
	pushup(x);if (!goal) root=x;
}
int find(int k,int goal)
{
	int x=root;
	while (base){
		if (k<=sz[ch[0][x]]) x=ch[0][x];
		else if (k==sz[ch[0][x]]+1) {splay(x,goal);return x;}
		else k-=sz[ch[0][x]]+1,x=ch[1][x];
	}
}
int build(int l,int r,int ff)
{
	if (l>r) return 0;
	int mid=l+r>>1;
	key[mid]=s[mid];fa[mid]=ff;
	ch[0][mid]=build(l,mid-1,mid);
	ch[1][mid]=build(mid+1,r,mid);
	pushup(mid);return mid;
}
ull cal(int l,int r)
{
	find(l,0);find(r+2,root);
	return hash[ch[0][ch[1][root]]];
}
int main()
{
	pw[0]=1;
	for (int i=1;i<N;++i) pw[i]=pw[i-1]*base;
	scanf("%s",s+2);n=strlen(s+2);
	root=build(1,n+2,0);
	m=gi();n+=2;
	while (m--)
	{
		char opt=getchar();
		while (opt!='Q'&&opt!='R'&&opt!='I') opt=getchar();
		if (opt=='Q')
		{
			int x=gi(),y=gi();if (x>y) swap(x,y);
			int l=1,r=n-y-1,ans=0;
			while (l<=r)
			{
				int mid=l+r>>1;
				if (cal(x,x+mid-1)==cal(y,y+mid-1)) ans=mid,l=mid+1;
				else r=mid-1;
			}
			printf("%d\n",ans);
		}
		if (opt=='R')
		{
			int x=gi();x=find(x+1,0);
			key[x]=getchar();pushup(x);
		}
		if (opt=='I')
		{
			int x=gi(),y=find(x+1,0),z=find(x+2,root);
			key[++n]=getchar();ch[0][fa[n]=z]=n;
			splay(n,0);
		}
	}
	return 0;
}
posted @ 2018-04-13 15:42  租酥雨  阅读(214)  评论(0编辑  收藏  举报