bzoj1014 [JSOI2008]火星人prefix ( splay + hash )

来源:互联网 发布:美容院微管理软件 编辑:程序博客网 时间:2024/05/16 12:05

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

专心,专心。

不理我算啦 (′へ` )