zoukankan      html  css  js  c++  java
  • [BZOJ 1014][JSOI2008]火星人prefix(Splay+二分+hash)

    Description

    火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:madamimadam,
    我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m 现在,
    火星人定义了一个函数LCQ(x, y),表示:该字符串中第x个字符开始的字串,与该字符串中第y个字符开始的字串
    ,两个字串的公共前缀的长度。比方说,LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0 在研究LCQ函数的过程
    中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出LCQ函数的值;同样,
    如果求出了LCQ函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取LCQ函数的快速
    算法,但不甘心认输的地球人又给火星人出了个难题:在求取LCQ函数的同时,还可以改变字符串本身。具体地说
    ,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此
    复杂的问题中,火星人是否还能够做到很快地求取LCQ函数的值。

    Solution

    看到LongestComonQianzhui2333手动滑稽

    如果不是很了解的话建议阅读《算法竞赛入门经典训练指南》3.4.3基于哈希值的LCP算法

    用Splay维护一下

      t[x].hash=t[lc(x)].hash+(t[x].val-'a')*base[t[lc(x)].siz]+t[rc(x)].hash*base[t[lc(x)].siz+1]  

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #define MAXN 100005
    #define lc(x) t[x].ch[0]
    #define rc(x) t[x].ch[1]
    #define Min(a,b) (a<b?a:b)
    using namespace std;
    int m,root,siz;
    char s[MAXN];
    unsigned long long base[MAXN];
    struct Node{
        int ch[2],father,siz;
        unsigned long long hash;
        char val;
        Node(){ch[0]=ch[1]=father=siz=hash=0;}
    }t[MAXN];
    int Read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(c=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    void Update(int x)
    {
        t[x].siz=t[lc(x)].siz+t[rc(x)].siz+1;
        t[x].hash=(t[x].val-'a')*base[t[lc(x)].siz];
        t[x].hash+=t[lc(x)].hash+t[rc(x)].hash*base[t[lc(x)].siz+1];
    }
    void Rotate(int x,int &k)
    {
        int y=t[x].father;
        int z=t[y].father;
        int p=(t[y].ch[0]==x)?0:1;
        if(y==k)k=x;
        else
        {
            if(t[z].ch[0]==y)t[z].ch[0]=x;
            else t[z].ch[1]=x;
        }
        t[x].father=z;
        t[y].ch[p]=t[x].ch[p^1];
        t[t[x].ch[p^1]].father=y;
        t[x].ch[p^1]=y;
        t[y].father=x;
        Update(y);Update(x);
    }
    void Splay(int x,int &k)
    {
        while(x!=k)
        {
            int y=t[x].father;
            int z=t[y].father;
            if(y!=k)
            {
                if((t[y].ch[0]==x)^(t[z].ch[0]==y))
                Rotate(x,k);
                else Rotate(y,k);
            }
            Rotate(x,k);
        }
    }
    int Build(int l,int r,int f)
    {
        if(l>r)return 0;
        int now=(l+r)>>1;
        t[now].father=f;
        t[now].val=s[now];
        t[now].ch[0]=Build(l,now-1,now);
        t[now].ch[1]=Build(now+1,r,now);
        Update(now);
        return now;
    }
    int Find(int x,int k)
    {
        if(!x)return 0; 
        if(t[lc(x)].siz>=k)return Find(lc(x),k);
        if(t[lc(x)].siz+1<k)return Find(rc(x),k-t[lc(x)].siz-1);
        return x;
    }
    int check(int x,int y)
    {
        int a=Find(root,x),b=Find(root,y+2);
        Splay(a,root);Splay(b,rc(root));
        return t[lc(rc(root))].hash;
    }
    void Query(int x,int y)
    {
        int l=1,r=Min(siz-x,siz-y)-1,ans=0;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(x,x+mid-1)==check(y,y+mid-1))
            ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d
    ",ans);
    }
    void Change(int x,char d)
    {
        int a=Find(root,x+1);
        Splay(a,root);
        t[a].val=d;Update(a);
    }
    void Insert(int x,char d)
    {
        int a=Find(root,x+1),b=Find(root,x+2);
        Splay(a,root);Splay(b,rc(root));
        siz++;t[rc(root)].ch[0]=siz;
        t[siz].val=d,t[siz].father=rc(root);
        Update(siz);Update(rc(root));Update(root);
    }
    int main()
    {
        base[0]=1;
        for(int i=1;i<MAXN;i++)base[i]=base[i-1]*27;
        scanf("%s",s+2);
        siz=strlen(s+2)+2;
        s[1]=s[siz]=0;
        m=Read();
        root=Build(1,siz,0);
        for(int i=1;i<=m;i++)
        {
            char opt,d;int x,y;
            opt=getchar();
            while(opt<'A'||opt>'Z')opt=getchar();
            switch(opt)
            {
                case 'Q':
                    x=Read();y=Read();
                    Query(x,y);
                    break;
                case 'R':
                    x=Read();
                    d=getchar();while(d<'a'||d>'z')d=getchar();
                    Change(x,d);
                    break;
                case 'I':
                    x=Read();
                    d=getchar();while(d<'a'||d>'z')d=getchar();
                    Insert(x,d);
                    break;
            }   
        }
        return 0;
    }
  • 相关阅读:
    学习进度第七周
    NABCD---生活日历
    学习进度第六周
    人月神话阅读笔记(3)
    人月神话阅读笔记(2)
    人月神话阅读笔记(1)
    石家庄地铁查询(双人项目)
    学习进度第五周
    学习进度第四周
    返回一个整数数组中最大子数组的和。(续2)---二维数组
  • 原文地址:https://www.cnblogs.com/Zars19/p/6659248.html
Copyright © 2011-2022 走看看