LCPhash求解

今天学习了一种用hash求解lcp问题的方法。

把一段内的hash表示为某个数x的递增次方乘上字符串相应位置的字母对应值,然后二分长度,判断两段的hash值是否相等就可以了。

hash值可以用unsigned long long保存,这种类型能在溢出的时候自动mod2^64(看到书上说的)。

 

cogs1849 jsoi火星人prefix

题目大意:对于一个字符串,有修改、插入和查询x、y位置开始的最长公共字串的长度三种操作。

思路:使用这种方法,在fhqTREEP上实现的。(但是常数比较大,所以bzoj上t掉了。。。)

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cstdlib>

#include<ctime>

#define xx 10007

#define sigmasiz 26

#define maxnode 100005

using namespace std;

unsigned long long mi[maxnode]={0};

struct Node{

    Node* ch[2];

    char cc;

    int siz,r;

    unsigned long long hash;

    Node(char cc):cc(cc){ch[0]=ch[1]=NULL;r=rand();siz=1;hash=(cc-'a')+1;}

    void updata()

    {

        siz=1;hash=0;

        if (ch[0]!=NULL)

        {

            siz+=ch[0]->siz;

            hash+=ch[0]->hash;

        }

        hash+=mi[siz-1]*(cc-'a'+1);

        if (ch[1]!=NULL)

        {

            hash+=ch[1]->hash * mi[siz];

            siz+=ch[1]->siz;

        }

    }

}*root;

char ss[maxnode];

int n;

Node* merge(Node *aa,Node *bb)

{

    if (aa==NULL) return bb;

    if (bb==NULL) return aa;

    if (aa->r < bb->r)

    {

        aa->ch[1]=merge(aa->ch[1],bb);

        if (aa!=NULL) aa->updata(); return aa;

    }

    else

    {

        bb->ch[0]=merge(aa,bb->ch[0]);

        if (bb!=NULL) bb->updata(); return bb;

    }

}

void split(Node *o,Node* &aa,Node* &bb,int x)

{

    if (o==NULL){aa=bb=NULL;return;}

    if (x==0){aa=NULL;bb=o;return;}

    if (x==o->siz){aa=o;bb=NULL;return;}

    if ((o->ch[0]==NULL ? 0 : o->ch[0]->siz)>=x)

    {

        split(o->ch[0],aa,bb,x);

        o->ch[0]=bb;o->updata();bb=o;

    }

    else

    {

        split(o->ch[1],aa,bb,x-(o->ch[0]==NULL? 0 : o->ch[0]->siz)-1);

        o->ch[1]=aa;o->updata();aa=o;

    }

}

void change(Node* &o,int x,char c)

{

    Node *a,*b,*y,*z;

    split(o,a,b,x-1);split(b,y,z,1);

    y=new Node(c);b=merge(y,z);o=merge(a,b);

}

void ins(Node* &o,int x,char c)

{

    Node *a,*b,*y,*z;

    split(o,a,b,x);y=new Node(c);

    z=merge(a,y);o=merge(z,b);++n;

}

unsigned long long calc(Node* o,int z,int ll)

{

    Node *a,*b,*x,*y;

    unsigned long long sum;

    split(o,a,b,z-1);split(b,x,y,ll);

    if (x!=NULL) sum=x->hash;

    else sum=0;

    b=merge(x,y);o=merge(a,b);

    return sum;

}

int ask(Node* o,int x,int y)

{

    Node *a,*b,*p,*q;

    int l,r,mid,ss;

    l=0;r=ss=min(n-x+1,n-y+1);

    while(l<r)

    {

        mid=(l+r)/2;

        if (calc(o,x,ss-mid)==calc(o,y,ss-mid)) r=mid;

        else l=mid+1;

    }

    return ss-l;

}

int main()

{

    int i,j,m,ll,a,b;

    char kk,c;

    mi[0]=1;root=NULL;

    for (i=1;i<maxnode;++i) mi[i]=mi[i-1]*xx;

    scanf("%s",&ss);n=strlen(ss);

    for (i=0;i<n;++i) 

    {

        Node *o;

        o=new Node(ss[i]);

        root=merge(root,o);

    }

    scanf("%d",&m);

    for (i=1;i<=m;++i)

    {

        while(kk=getchar())

            if (kk>='A'&&kk<='Z') break;

        if (kk=='Q') 

        {

            scanf("%d%d",&a,&b);

            printf("%d\n",ask(root,a,b));

        }

        if (kk=='R')

        {

            scanf("%d",&a);

            while(c=getchar())

              if (c>='a'&&c<='z') break;

            change(root,a,c);

        }

        if (kk=='I')

        {

            scanf("%d",&a);

            while(c=getchar())

              if (c>='a'&&c<='z') break;

            ins(root,a,c);

        }

    }

}
View Code

 (把unsigned long long改为unsigned int,再加上inline,就从bzoj上a掉了。。。)

#include<iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#include<cstdlib>

#include<ctime>

#define xx 10007

#define sigmasiz 26

#define maxnode 100005

using namespace std;

unsigned int mi[maxnode]={0};

struct Node{

    Node* ch[2];

    char cc;

    int siz,r;

    unsigned int hash;

    Node(char cc):cc(cc){ch[0]=ch[1]=NULL;r=rand();siz=1;hash=(cc-'a')+1;}

    void updata()

    {

        siz=1;hash=0;

        if (ch[0]!=NULL)

        {

            siz+=ch[0]->siz;

            hash+=ch[0]->hash;

        }

        hash+=mi[siz-1]*(cc-'a'+1);

        if (ch[1]!=NULL)

        {

            hash+=ch[1]->hash * mi[siz];

            siz+=ch[1]->siz;

        }

    }

}*root;

char ss[maxnode];

int n;

inline Node* merge(Node *aa,Node *bb)

{

    if (aa==NULL) return bb;

    if (bb==NULL) return aa;

    if (aa->r < bb->r)

    {

        aa->ch[1]=merge(aa->ch[1],bb);

        if (aa!=NULL) aa->updata(); return aa;

    }

    else

    {

        bb->ch[0]=merge(aa,bb->ch[0]);

        if (bb!=NULL) bb->updata(); return bb;

    }

}

inline void split(Node *o,Node* &aa,Node* &bb,int x)

{

    if (o==NULL){aa=bb=NULL;return;}

    if (x==0){aa=NULL;bb=o;return;}

    if (x==o->siz){aa=o;bb=NULL;return;}

    if ((o->ch[0]==NULL ? 0 : o->ch[0]->siz)>=x)

    {

        split(o->ch[0],aa,bb,x);

        o->ch[0]=bb;o->updata();bb=o;

    }

    else

    {

        split(o->ch[1],aa,bb,x-(o->ch[0]==NULL? 0 : o->ch[0]->siz)-1);

        o->ch[1]=aa;o->updata();aa=o;

    }

}

inline void change(Node* &o,int x,char c)

{

    Node *a,*b,*y,*z;

    split(o,a,b,x-1);split(b,y,z,1);

    y=new Node(c);b=merge(y,z);o=merge(a,b);

}

inline void ins(Node* &o,int x,char c)

{

    Node *a,*b,*y,*z;

    split(o,a,b,x);y=new Node(c);

    z=merge(a,y);o=merge(z,b);++n;

}

inline unsigned int calc(Node* o,int z,int ll)

{

    Node *a,*b,*x,*y;

    unsigned int sum;

    split(o,a,b,z-1);split(b,x,y,ll);

    if (x!=NULL) sum=x->hash;

    else sum=0;

    b=merge(x,y);o=merge(a,b);

    return sum;

}

inline int ask(Node* o,int x,int y)

{

    Node *a,*b,*p,*q;

    int l,r,mid,ss;

    l=0;r=ss=min(n-x+1,n-y+1);

    while(l<r)

    {

        mid=(l+r)/2;

        if (calc(o,x,ss-mid)==calc(o,y,ss-mid)) r=mid;

        else l=mid+1;

    }

    return ss-l;

}

int main()

{

    int i,j,m,ll,a,b;

    char kk,c;

    mi[0]=1;root=NULL;

    for (i=1;i<maxnode;++i) mi[i]=mi[i-1]*xx;

    scanf("%s",&ss);n=strlen(ss);

    for (i=0;i<n;++i) 

    {

        Node *o;

        o=new Node(ss[i]);

        root=merge(root,o);

    }

    scanf("%d",&m);

    for (i=1;i<=m;++i)

    {

        while(kk=getchar())

            if (kk>='A'&&kk<='Z') break;

        if (kk=='Q') 

        {

            scanf("%d%d",&a,&b);

            printf("%d\n",ask(root,a,b));

        }

        if (kk=='R')

        {

            scanf("%d",&a);

            while(c=getchar())

              if (c>='a'&&c<='z') break;

            change(root,a,c);

        }

        if (kk=='I')

        {

            scanf("%d",&a);

            while(c=getchar())

              if (c>='a'&&c<='z') break;

            ins(root,a,c);

        }

    }

}
View Code

 

你可能感兴趣的:(hash)