zoukankan      html  css  js  c++  java
  • BZOJ 1014 [JSOI2008]火星人prefix

    字符串Hash+二分+平衡树(fhq_treap)

    如果没有插入和改变字符的操作,字符串Hash是可以处理出LCP的值的

    就是先处理出原字符串的前缀$hash$值,然后对于两个开始的位置二分枚举LCP的长度

    然后就是利用前缀和处理出$l$,$r$区间的$hash$值,进行比较即可

    但是本题有插入和改变字符的操作

    那么就需要用平衡树维护字符串的$hash$值

    整个题中要用到平衡树的就是要查找某一区间的$hash$值

    那么以下标建立一棵平衡树,对于每个节点记录该节点和其子树的hash值

    那么一个节点的$hash$直接就是

    $hash_{rson}+base^{size[rson]}*ch+base^{size[rson]+1}*hash_{lson}$

    此处用的是fhq_treap维护整个字符串的$hash$值

    #include <bits/stdc++.h>
    #define base 131
    using namespace std;
    const int MAXN=101000;
    int m,root,tot,len;
    char g[MAXN];
    int z[MAXN];
    struct node
    {
        int ha;
        char c;
        int son[2],si,key;
    }sh[MAXN];
    int newnode(char ch)
    {
        tot++;
        sh[tot].c=ch;
        sh[tot].ha=(int)ch;
        sh[tot].si=1;
        sh[tot].key=rand();
        return tot;
    }
    void pushup(int x)
    {
        sh[x].si=sh[sh[x].son[0]].si+sh[sh[x].son[1]].si+1;
        sh[x].ha=sh[sh[x].son[1]].ha+z[sh[sh[x].son[1]].si]*(int)sh[x].c+z[sh[sh[x].son[1]].si+1]*sh[sh[x].son[0]].ha;//维护当前节点的hash
    }
    int build(int ll,int rr)
    {
        int mid,cur;
        mid=(ll+rr)>>1;
        cur=newnode(g[mid]);
        if (ll==rr)
        {
            pushup(cur);
            return cur;
        }
        if (ll<=mid-1)
          sh[cur].son[0]=build(ll,mid-1);
        if (mid+1<=rr)
          sh[cur].son[1]=build(mid+1,rr);
        pushup(cur);
        return cur;
    }
    void split(int now,int k,int &x,int &y)//fhq_treap的基本操作,此处以第k个划分
    {
        if (now==0)
        {
            x=0;
            y=0;
            return;
        }
        if (sh[sh[now].son[0]].si>=k)
        {
            y=now;
            split(sh[now].son[0],k,x,sh[now].son[0]);
        }
        else
        {
            x=now;
            split(sh[now].son[1],k-1-sh[sh[now].son[0]].si,sh[now].son[1],y);
        }
        pushup(now);
    }
    int merge(int x,int y)
    {
        if (x==0)
          return y;
        if (y==0)
          return x;
        if (sh[x].key<=sh[y].key)
        {
            sh[x].son[1]=merge(sh[x].son[1],y);
            pushup(x);
            return x;
        }
        else
        {
            sh[y].son[0]=merge(x,sh[y].son[0]);
            pushup(y);
            return y;
        }
    }
    void insert(int k,char ch)
    {
        int a,b;
        split(root,k,a,b);
        root=merge(merge(a,newnode(ch)),b);
    }
    void del(int k)
    {
        int a,b,c;
        split(root,k,a,b);
        split(a,k-1,a,c);
        c=merge(sh[c].son[0],sh[c].son[1]);
        root=merge(merge(a,b),c);
    }
    void change(int k,char ch)
    {
        int a,b,c;
        split(root,k-1,a,b);
        split(b,1,b,c);
        sh[b].c=ch;
        sh[b].ha=(int)ch;
        root=merge(a,merge(b,c));
    }
    int get(int l,int r)//求出某一区间的hash值
    {
        int a,b,c;
        split(root,l-1,a,b);
        split(b,r-l+1,b,c);
        int h;
        h=sh[b].ha;
        b=merge(b,c);
        root=merge(a,b);
        return h;
    }
    int query(int x,int y)
    {
        if (get(x,x)!=get(y,y))
          return 0;
        int l,r;
        l=0;r=min(len-x+1,len-y+1);
        while (l<r)//二分查找答案
        {
            int mid;
            mid=l+((r-l+1)>>1);
            if (get(x,x+mid-1)==get(y,y+mid-1))
              l=mid;
            else
              r=mid-1;
        }
        return l;
    }
    int main()
    {
        srand(time(0));
        scanf("%s",g+1);
        len=strlen(g+1);
        z[0]=1;
        for (int i=1;i<=100000;i++)
          z[i]=z[i-1]*base;
        root=build(1,len);
        scanf("%d",&m);
        for (int i=1;i<=m;i++)
        {
            char op[3];
            scanf("%s",op);
            if (op[0]=='Q')
            {
                int x,y;
                scanf("%d%d",&x,&y);
                printf("%d
    ",query(x,y));
            }
            if (op[0]=='R')
            {
                int x;
                char d[5];
                scanf("%d%s",&x,d);
                change(x,d[0]);
            }
            if (op[0]=='I')
            {
                int x;
                char d[5];
                scanf("%d%s",&x,d);
                insert(x,d[0]);
                len++;
            }
        }
    }
  • 相关阅读:
    Array 数组对象
    Math对象
    String 字符串对象
    Date 日期对象
    一个简单的计算器
    如何判断一个js对象是否一个DOM对象
    筛选if 运用
    移动端前端笔记大全
    一个元素的偏移的方法
    如果判断一个dom 对像?
  • 原文地址:https://www.cnblogs.com/huangchenyan/p/11331591.html
Copyright © 2011-2022 走看看