【BZOJ】1014 [JSOI2008]火星人prefix

时间:2023-03-09 06:50:57
【BZOJ】1014 [JSOI2008]火星人prefix

【算法】splay

【题解】对于每个结点维护其子树串的hash值,前面为高位,后面为低位。

sum[x]=sum[L]*base[s[R]+1]+A[x]*base[s[R]]+sum[R],其中sum为哈希,base为乘权,A为数值(即字符)。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=,inf=0x3f3f3f3f,bases=;
int f[maxn],t[maxn][],s[maxn],A[maxn],a[maxn],sz=,root,n;
unsigned long long sum[maxn],a_,b_,b[maxn];
int Node(int fa,int num)
{
sz++;
f[sz]=fa;t[sz][]=t[sz][]=;
s[sz]=;A[sz]=sum[sz]=num;
return sz;
}
void count(int x)
{
s[x]=s[t[x][]]++s[t[x][]];
sum[x]=sum[t[x][]]*b[s[t[x][]]+]+1ull*A[x]*b[s[t[x][]]]+sum[t[x][]];
}
void build(int fa,int &x,int l,int r)
{
if(l>r)return;
int mid=(l+r)>>;
x=Node(fa,a[mid]);
build(x,t[x][],l,mid-);
build(x,t[x][],mid+,r);
count(x);
}
void rotate(int x)
{
int k=x==t[f[x]][];
int y=f[x];
t[y][k]=t[x][!k];f[t[x][!k]]=y;
if(f[y])t[f[y]][y==t[f[y]][]]=x;f[x]=f[y];f[y]=x;
t[x][!k]=y;
sum[x]=sum[y];s[x]=s[y];
count(y);
}
void splay(int x,int r)
{
for(int fa=f[r];f[x]!=fa;)
{
if(f[f[x]]==fa){rotate(x);return;}
int X=x==t[x][],Y=f[x]==t[f[f[x]]][];
if(X^Y)rotate(x),rotate(x);
else rotate(f[x]),rotate(x);
}
}
void find(int &x,int k)
{
for(int i=x;i;)
{
if(k<=s[t[i][]]){i=t[i][];continue;}
if(k==s[t[i][]]+){splay(i,x);x=i;return;}
k-=s[t[i][]]+;i=t[i][];
}
}
bool work(int x,int y,int longs)
{
if(x+longs->n||y+longs->n)return ;
find(root,x);find(t[root][],longs+);
a_=sum[t[t[root][]][]];
find(root,y);find(t[root][],longs+);
b_=sum[t[t[root][]][]];
if(a_==b_)return ;
return ;
}
void ask()
{
int x,y;
scanf("%d%d",&x,&y);
int l=,r=maxn;
while(l<r)
{
int mid=(l+r)>>;
if(work(x,y,mid))l=mid+;
else r=mid;
}
printf("%d\n",l-);
}
void repair()
{
int x;char c;
scanf("%d %c",&x,&c);
find(root,x+);
A[root]=c-'a'+;
count(root);
}
void insert()
{
n++;
int x;char c;
scanf("%d %c",&x,&c);
find(root,x+);find(t[root][],);
int y=Node(t[root][],c-'a'+);
t[t[root][]][]=y;
f[y]=t[root][];
count(t[root][]);
count(root);
}
char str[maxn];
int main()
{
scanf("%s",str+);
n=strlen(str+);
for(int i=;i<=n;i++)a[i]=str[i]-'a'+;
b[]=;
for(int i=;i<=maxn;i++)b[i]=b[i-]*bases;
root=a[]=a[n+]=;
build(,root,,n+);
int m;
scanf("%d",&m);
for(int i=;i<=m;i++)
{
scanf("%s",str);//不要用%c会读空格,用%s读到空格会停。
if(str[]=='Q')ask();
if(str[]=='R')repair();
if(str[]=='I')insert();
}
return ;
}

update:现在已改用fhq-treap代替splay。