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
",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
",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
原文地址:https://www.cnblogs.com/Rivendell/p/4621112.html