bzoj1014 [JSOI2008]火星人prefix
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1014
题意:
给定一个字符串,比方说,有这样一个字符串:madamimadam,
我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m
有3种操作:
1、询问。语法:Q x y,x, y均为正整数。
功能:计算LCQ(x, y)
2、修改。语法:R x d,x是正整数,d是字符。
功能:将字符串中第x个数修改为字符d。
限制:x不超过当前字符串长度。
3、插入:语法:I x d,x是非负整数,d是字符。
功能:在字符串第x个字符之后插入字符d,如果x = 0,则在字符串开头插入。
限制:x不超过当前字符串长度。
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。
数据范围
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
题解:
复习一发spaly。
首先我们知道二分比较hash值可以log地得到两个串的最长公共前缀,而给出的替换和插入操作可以让我们想到splay维护。
于是我们用splay维护字符串,每个节点上存有它控制的区间的hash值。每次查询两个后缀的最长公共前缀,只需要二分长度,然后把这个区间转上去,重算hash值,比较这两个区间的hash值是否相同即可。
( wa点:size没搞对,二分的时候越界了。改回来时影响了关于查询的两个串是同一个串的情况,其实不用特判。)
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#define LL unsigned long long
using namespace std;
const int N=100010;
const int M=150010;
const LL base=131;
int root,tail=0,fa[N];
struct node
{
int ch[2],size;
LL val,key;
}tr[N];
int m,len;
LL mi[N];
char s[M],opt[5];
void update(int x)
{
int ls=tr[x].ch[0]; int rs=tr[x].ch[1];
tr[x].key=tr[x].val; tr[x].size=1;
if(rs)
{
tr[x].size+=tr[rs].size;
tr[x].key=tr[x].key*mi[tr[rs].size]+tr[rs].key;
}
if(ls)
{
tr[x].size+=tr[ls].size;
tr[x].key=tr[ls].key*mi[tr[x].size-tr[ls].size]+tr[x].key;
}
return;
}
void build(int &nd,int lf,int rg,int f)
{
if(lf>rg) return;
nd=++tail; fa[nd]=f;
tr[nd].ch[0]=tr[nd].ch[1]=0;
if(lf==rg)
{
tr[nd].size=1;
tr[nd].val=tr[nd].key=(int)s[lf];
return;
}
int mid=(lf+rg)>>1;
tr[nd].val=s[mid];
build(tr[nd].ch[0],lf,mid-1,nd);
build(tr[nd].ch[1],mid+1,rg,nd);
update(nd);
}
int find(int nd,int pos)
{
int ls=tr[nd].ch[0]; int rs=tr[nd].ch[1];
if(pos==tr[ls].size+1) return nd;
else if(pos<=tr[ls].size) return find(tr[nd].ch[0],pos);
else return find(tr[nd].ch[1],pos-tr[ls].size-1);
}
void rotate(int x,int &k)
{
int y=fa[x]; int z=fa[y];
int l,r;
if(x==tr[y].ch[0]) l=0; else l=1; r=l^1;
if(y==k) k=x;
else if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;
fa[x]=z;
tr[y].ch[l]=tr[x].ch[r];
fa[tr[x].ch[r]]=y;
tr[x].ch[r]=y; fa[y]=x;
update(y); update(x);
}
void splay(int x,int &k)
{
while(x!=k)
{
int y=fa[x]; int z=fa[y];
if(y!=k)
{
if((tr[y].ch[0]==x)^(tr[z].ch[0]==y))
rotate(x,k);
else rotate(y,k);
}
rotate(x,k);
}
}
LL check(int l,int r)
{
splay(l,root); splay(r,tr[l].ch[1]);
int nd=tr[tr[l].ch[1]].ch[0];
return tr[nd].key;
}
int query(int p,int q) //询问x,y的lcp
{
int x=find(root,p); int y=find(root,q);
if(tr[x].val!=tr[y].val) return 0;
int lx,rx,ly,ry;
lx=find(root,p-1); ly=find(root,q-1);
int sz=tr[root].size;
int lf=1; int rg=min(sz-p,sz-q);
while(lf+1<rg)
{
int mid=(lf+rg)>>1;
rx=find(root,p+mid);
LL v1=check(lx,rx);
ry=find(root,q+mid);
LL v2=check(ly,ry);
if(v1==v2) lf=mid;
else rg=mid;
}
int ans;
rx=find(root,p+rg);
LL v1=check(lx,rx);
ry=find(root,q+rg);
LL v2=check(ly,ry);
if(v1==v2) ans=rg;
else ans=lf;
return ans;
}
int main()
{
mi[0]=1;
for(int i=1;i<N;i++)
mi[i]=mi[i-1]*base;
scanf("%s",s+2);
len=strlen(s+2);
tr[0].size=0;
build(root,1,len+2,0);
scanf("%d",&m);
while(m--)
{
scanf("%s",opt);
if(opt[0]=='Q')
{
int x,y;
scanf("%d%d",&x,&y);
x++; y++;
printf("%d\n",query(x,y));
}
else if(opt[0]=='R')
{
int pos; char ccc[5];
scanf("%d",&pos); scanf("%s",ccc);
pos++;
int c=(int)ccc[0];
int nd=find(root,pos);
splay(nd,root);
tr[nd].val=c;
update(nd);
}
else
{
int pos; char ccc[5];
scanf("%d",&pos); scanf("%s",ccc);
pos++;
int c=(int)ccc[0];
int f=find(root,pos);
splay(f,root);
int nd=++tail;
tr[nd].val=c;
tr[nd].ch[1]=tr[f].ch[1]; fa[tr[nd].ch[1]]=nd;
tr[f].ch[1]=nd;fa[nd]=f;
tr[nd].ch[0]=0;
update(nd); update(f);
}
}
return 0;
}
专心,专心。
不理我算啦 (′へ` )