フェイス質問
問題の意味
文字列を維持するため、文字、文字修正の挿入をサポートし、最長共通接頭辞と接尾辞は2を必要としていました。
問題の解決策
メンテナンス列バランス木、各追加ノードは、ツリーの子ノードは、文字列のハッシュ値を表して維持します。スプレイは、この質問を書き込む場合、この時間は更新関連するサブツリーノードのハッシュ値のすべての一頭の回転が正しい保証できる場合にのみ、ノード情報を維持するために、バランスのとれたツリーの実装として選択します。
ハッシュ用いて、式文字列\(ハッシュ(S)=( {| | S}(ID(S_I)-96)\ CDOT 31 ^ {| | S -i})\ MOD \ sum_ {I = 1} ^を^ {64} 2 \) (\(96 \) '' ASCIIコードである( - 1 \)\ \ (31 \)と\(2 ^ {64} \)任意容易に競合することができますハッシュ乗数およびモジュラス)、木の左と右のサブツリーと簡潔であってもよいが、ハッシュ値は、によってもよいが得られる(ハッシュ(S_ {I \ \ドットJ})=ハッシュ(S_ {1 \ ドットJ}) - 31 ^ { J-I + 1} \ CDOTハッシュ(S_ {1つの\ドットI-1})\ MOD 2 ^ {64} \) のハッシュ値列の接頭文字列のいずれかで決定されますハッシュ値、及び左サブツリーのルートプレフィックスのハッシュ値がハであり、その場合には、単にルートノードスプレー木にハッシュ値のプレフィックス文字列の回転を見つける必要がある接頭辞の後の最初の文字を、サブストリングギリシャの値。文字列「$」文字の一方の端の余分加えて、文字列全体の誤りのハッシュ値を防ぐためにしようとするとき。
修飾された後、ルートノードに関連するだけの挿入及び回転配置した後サブツリー関連ハッシュ値変更操作にノードを更新。答えは最長の共通接頭文字列を評価するとき、それぞれが2つのサブ検査に対応し、二部であることができる\(ハッシュ(S_ {X \ドットX + M})、ハッシュ(S_ {Y \ドットY + Mを})\) と同じです。
コード
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
using namespace std;
typedef unsigned long long ull;
const int maxn=1e5+5;
const ull mul=31;
vector<ull> powarr;
ull getpow(int n){
while (powarr.size()<=n)
powarr.push_back(powarr.back()*mul);
return powarr[n];
}
struct Splay_Tree{
struct node{
node *fa,*ch[2];
char val;
int size;
ull hash;
};
node *root;
node *const nil;
node *nnode(char ch){
node *nd=new node();
nd->fa=nd->ch[0]=nd->ch[1]=nil;
nd->val=ch; nd->size=1; nd->hash=nd->val-'a'+1;
return nd;
}
Splay_Tree():nil(new node()){
nil->fa=nil->ch[0]=nil->ch[1]=nil;
nil->val=0; nil->size=0; nil->hash=0;
root=nnode('$');
}
int size(){ return root->size-1; }
void update(node *nd){
nd->size=0; nd->hash=0;
nd->size+=nd->ch[0]->size;
nd->hash*=getpow(nd->ch[0]->size);
nd->hash+=nd->ch[0]->hash;
nd->size+=1;
nd->hash*=mul;
nd->hash+=nd->val-'a'+1;
nd->size+=nd->ch[1]->size;
nd->hash*=getpow(nd->ch[1]->size);
nd->hash+=nd->ch[1]->hash;
}
bool getid(node *u){
return u==u->fa->ch[1];
}
void rotate(node *u){
node *v,*w,*x;
bool b,c;
if (u==nil) return;
v=u->fa;
if (v==nil) return;
b=getid(u); c=getid(v);
w=v->fa; x=u->ch[!b];
v->ch[b]=x; if (x!=nil) x->fa=v;
u->ch[!b]=v; v->fa=u;
if (w!=nil) w->ch[c]=u; u->fa=w;
update(v); update(u);
}
void splay(node *u){
while (u->fa->fa!=nil){
if (getid(u)==getid(u->fa)){
rotate(u->fa); rotate(u);
}
else {
rotate(u); rotate(u->fa);
}
}
if (u->fa!=nil) rotate(u);
root=u;
}
void find(int x){
node *u=root;
bool b;
while (true){
b=x>u->ch[0]->size;
x-=b?u->ch[0]->size+1:0;
if (!x) break;
u=u->ch[b];
}
splay(u);
}
ull query(int x){
find(x+1);
return root->ch[0]->hash;
}
ull hash(int x,int y){
return query(y)-query(x)*getpow(y-x);
}
void change(int x,char ch){
find(x);
root->val=ch;
update(root);
}
void insert(int x,char ch){
find(x+1);
node *u,*v,*w;
u=nnode(ch);
v=root->ch[0];
w=root;
u->ch[0]=v;
if (v!=nil) v->fa=u;
u->ch[1]=w;
w->fa=u;
w->ch[0]=nil;
update(w);
update(u);
root=u;
}
};
Splay_Tree tree;
char s[maxn],a[10],b[10];
int query(int x,int y){
int l,r,m;
l=0; r=tree.size()-y+2;
while (r-l>1){
m=(l+r)/2;
if (tree.hash(x-1,x+m-1)==tree.hash(y-1,y+m-1))
l=m;
else r=m;
}
return l;
}
int main(){
int i,m,x,y;
powarr.clear(); powarr.push_back(1);
scanf("%s",s);
for (i=strlen(s)-1;i>=0;i--)
tree.insert(0,s[i]);
scanf("%d",&m);
while (m--){
scanf("%s",a);
switch (a[0]){
case 'Q':
scanf("%d%d",&x,&y);
if (x>y) swap(x,y);
printf("%d\n",query(x,y));
break;
case 'R':
scanf("%d%s",&x,b);
tree.change(x,b[0]);
break;
case 'I':
scanf("%d%s",&x,b);
tree.insert(x,b[0]);
break;
}
}
return 0;
}