procedure2012
It's not worth it to know you're not worth it!

[关键字]:splay hash 二分

[题目大意]:给出一个字符串,求出给定的两个后缀的的最长公共前缀。在求的过程中会有改变或在某个位置添加字符的操作。

//============================================================================================

[分析]:一听最长公共前缀马上想到后缀数组,但因为是动态维护所以后缀数组也无能为力。可以把字符串想象成一个数组,于是变成了动态插入和改变一个序列,还要能快速找到两个子区间——splay。求最长公共前缀可以用二分答案加验证的方法,二分长度先提取出这个区间然后判断这个区间的根节点的hash值(实际就是这棵子树的hash)是否和另一个相同。hash值得判断可以用进制法:hash=ord(s[1])*270+ord(s[2])*271+……+ord(s[n])*27n-1,在旋转时更新hash值为:hash[lc]+s[v]*27^(size[lc]+1)+hash[rc]*27^(size[lc]+2)。插入操作和一般splay插入无异修改只要修改掉这个点的值和hash值就行了。

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;

const int MAXL=100015;
const int MOD=9875321;

struct node
{
    node *c[2],*f;
    int dat,size,hash;
}*root,SC[MAXL],*null;
char s[MAXL];
int m,SS;
int d[MAXL];

void Debug(node *v)
{
    if (v==null) return;
    Debug(v->c[0]);
    printf("%d ",v->dat);
    Debug(v->c[1]);
}

node *New(int d,int h,node *fa)
{
    node *e=SC+ ++SS;
    e->size=1,e->f=fa;
    e->c[1]=e->c[0]=null;
    e->dat=d,e->hash=h;
    return e;
}

void Update(node *v)
{
    if (v==null) return;
    v->size=v->c[0]->size+v->c[1]->size+1;
    v->hash=(long long)(v->c[0]->hash+(long long)v->dat*d[(v->c[0]->size+1)]+(long long)v->c[1]->hash*d[(v->c[0]->size+2)])%MOD;
}

void Prepare()
{
    SS=-1;
    null=NULL;
    null=New(0,0,NULL);
    null->size=0;
    root=New(0,0,null);
    root->c[1]=New(0,0,root);
    d[1]=1;
    for (int i=2;i<=100010;++i)
        d[i]=(d[i-1]*27)%MOD;
    Update(root);
}

void Rotate(node *x,int o)
{
    node *y=x->f;
    y->c[o]=x->c[!o];
    y->c[o]->f=y;
    x->f=y->f;
    if (y->f->c[0]==y)
        y->f->c[0]=x;
    else
        y->f->c[1]=x;
    x->c[!o]=y;
    y->f=x;
    if (y==root) root=x;
    Update(y);
}

void Splay(node *x,node *fa)
{
    while (x->f!=fa)
        if (x->f->f==fa)
            if (x->f->c[0]==x)
                Rotate(x,0);
            else
                Rotate(x,1);
        else
            if (x->f->f->c[0]==x->f)
                if (x->f->c[0]==x)
                    Rotate(x->f,0),Rotate(x,0);
                else
                    Rotate(x,1),Rotate(x,0);
            else    
                if (x->f->c[1]==x)
                    Rotate(x->f,1),Rotate(x,1);
                else
                    Rotate(x,0),Rotate(x,1);
    Update(x);
}

void Select(int k,node *fa)
{
    node *t=root;
    while (1)
    {
        if (k==t->c[0]->size+1) break;
        if (k<t->c[0]->size+1) t=t->c[0];
        if (k>t->c[0]->size+1) k-=t->c[0]->size+1,t=t->c[1];
    }
    Splay(t,fa);
}

int Hash(int x,int y)
{
    Select(x,null),Select(y+2,root);
    return root->c[1]->c[0]->hash;
}

void Ask(int x,int y)
{
    int ans=0,n=root->size-2;
    for (int i=1<<18;i;i>>=1)
        if (x+i-1<=n && y+i-1<=n && Hash(x,x+i-1)==Hash(y,y+i-1))
            ans+=i,x+=i,y+=i;
    printf("%d\n",ans);
}

void Ins(int x,char ch)
{
    Select(x+1,null),Select(x+2,root);
    root->c[1]->c[0]=New(ch-'a',ch-'a',root->c[1]);
    Splay(root->c[1]->c[0],null);
    //Debug(root),printf("\n");
}

void Rep(int x,char ch)
{
    Select(x,null),Select(x+2,root);
    node *v=root->c[1]->c[0];
    v->dat=ch-'a';
    v->hash=(long long)(v->c[0]->hash+(long long)v->dat*d[(v->c[0]->size+1)]+(long long)v->c[1]->hash*d[(v->c[0]->size+2)])%MOD;
    //Debug(root),printf("\n");
}

void Init()
{
    node *z,*t;
    Prepare();
    scanf("%s",s);
    int n=strlen(s);
    z=t=New(s[0]-'a',s[0]-'a',null);
    for (int i=1;i<n;++i)
        z=z->c[1]=New(s[i]-'a',s[i]-'a',z);
    root->c[1]->c[0]=t,t->f=root->c[1];
    Splay(z,null);
    //Debug(root),printf("\n");
}

void Solve()
{
    char ch; int x,y;
    scanf("%d",&m),scanf("%c",&ch);
    for (int i=1;i<=m;++i)
    {
        scanf("%c",&ch);
        if (ch=='Q') scanf("%d %d",&x,&y),Ask(x,y); else
        if (ch=='I') scanf("%d %c",&x,&ch),Ins(x,ch); else
            scanf("%d %c",&x,&ch),Rep(x,ch);
        scanf("%c",&ch);
    }
}

int main()
{
    freopen("in","r",stdin);
    freopen("out","w",stdout);
    Init();
    Solve();
    return 0;
}
posted on 2012-04-13 00:14  procedure2012  阅读(1042)  评论(0编辑  收藏  举报