• BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)


    描述


    http://www.lydsy.com/JudgeOnline/problem.php?id=1014

    给出一个字符串,有修改,插入,以及询问LCP(i,j)的操作.

    分析


    LCP在白书上面有介绍,(LCP(i,j))表示以第(i)位和以第(j)位开头的后缀的最长公共前缀.

    先考虑没有插入和修改操作的问题.我们可以用基于Hash的LCP算法.

    我们给每一个后缀一个Hash值.其中以第(i)为开头的后缀的Hash值为(H[i]=H[i+1]x+s[i]).

    其中(x)是随便一个什么数.例如:

    (H[4]=s[4])

    (H[3]=s[4]x+s[3])

    (H[2]=s[4]x^2+s[3]x+s[2])

    (H[1]=s[4]x^3+s[3]x^2+s[2]x+s[1])

    一般地有:

    $$H[i]=s[n]x^{n-i}+s[n-1]x^{n-1-i}+...+s[i+1]x+s[i]$$

    对于字符串(s[i]~s[i+L-1])(长度为L),定义它的Hash值为:

    $$Hash(i,L)=H[i]-H[i+L]x^L$$

    其实就是相当于把以(i)开头的后缀的Hash值有关(i+L)以及后面的部分都砍掉.

    当然这个Hash值可以定义为前缀的形式,和后缀的没有区别.

    但是注意,并不是字符串不同,Hash值一定不同,只是相同的概率极低,基本可以无视.

    至于计算,我们采用unsigned long long ,这样自然溢出相当于对(2^{64})取模.

    这样我们就可以判断字串((i,L))与((j,L))是否相等,二分(L)的值,取最大可行解即可.

     

    至于修改和插入操作?平衡树来解决咯.平衡树上每个结点的Hash值代表的是以该结点为根的子树代表的字符串的Hash值.

    p.s.

    1.复习了下Splay,好不熟练啊,还要多练习,不然药丸...

    2.调了好久发现是字符串读入的问题...(拍脸)

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 
     4 const int maxn=1e5+5;
     5 typedef unsigned long long ull;
     6 int n,m;
     7 ull p[maxn];
     8 char s[maxn];
     9 struct Splay{
    10     struct node{
    11         node* c[2],* f;
    12         int v,s; ull h;
    13         node(int v,node* t):v(v){ s=1;h=v;f=c[0]=c[1]=t; }
    14         bool d(){ return f->c[1]==this; }
    15         void setc(node* x,bool d){ c[d]=x; x->f=this; }
    16         void push_up(){
    17             s=c[0]->s+c[1]->s+1;
    18             h=c[0]->h+(ull)v*p[c[0]->s]+c[1]->h*p[c[0]->s+1];
    19         }
    20     }* root,* null;
    21     Splay(){
    22         null=new node(0,0);null->s=0;
    23         root=new node(0,null); root->setc(new node(0,null),1);
    24     }
    25     void rot(node* x){
    26         node* f=x->f; bool d=x->d();
    27         f->f->setc(x,f->d());
    28         f->setc(x->c[!d],d);
    29         x->setc(f,!d);
    30         f->push_up();
    31         if(f==root) root=x;
    32     }
    33     void splay(node* x,node *f){
    34         while(x->f!=f)
    35             if(x->f->f==f) rot(x);
    36             else x->d()==x->f->d()?(rot(x->f),rot(x)):(rot(x),rot(x));
    37         x->push_up();
    38     }
    39     node* kth(int k){
    40         for(node* t=root;t!=null;){
    41             int s=t->c[0]->s;
    42             if(k==s) return t;
    43             if(k>s) t=t->c[1], k-=s+1;
    44             else t=t->c[0];
    45         }
    46     }
    47     node* get_range(int l,int r){
    48         splay(kth(l-1),null);
    49         splay(kth(r+1),root);
    50         return root->c[1]->c[0];
    51     }
    52     void ins(int v,int pos){
    53         node *f=get_range(pos,pos);
    54         f->setc(new node(v,null),1); splay(f->c[1],null);
    55     }
    56     void chg(int v,int pos){
    57         node *x=get_range(pos,pos);
    58         x->v=v; splay(x,null);
    59     }
    60     int hash(int l,int r){ return get_range(l,r)->h; }
    61     node* build(int l,int r){
    62         if(l>r) return null;
    63         int m=l+(r-l)/2;
    64         node *t=new node(s[m]-'a'+1,null);
    65         t->setc(build(l,m-1),0);
    66         t->setc(build(m+1,r),1);
    67         t->push_up();
    68         return t;
    69     }
    70 }T;
    71 inline int read(int &x){ x=0;int k=1;char c;for(c=getchar();c<'0'||c>'9';c=getchar())if(c=='-')k=-1;for(;c>='0'&&c<='9';c=getchar())x=x*10+c-'0';return x*=k; }
    72 inline char read(char &c){ for(c=getchar();(c<'a'||c>'z')&&(c<'A'||c>'Z');c=getchar());return c; }
    73 int bsearch(int x,int y){
    74     int s=T.root->s-2;
    75     int l=0,r=min(s-x,s-y)+1,mid;
    76     while(l<r){
    77         mid=l+(r-l+1)/2;
    78         if(T.hash(x,x+mid-1)==T.hash(y,y+mid-1)) l=mid;
    79         else r=mid-1;
    80     }
    81     return l;
    82 }
    83 void init(){
    84     scanf("%s",s+1); n=strlen(s+1); read(m);
    85     p[0]=1;
    86     for(int i=1;i<maxn;i++) p[i]=p[i-1]*(ull)27;
    87     T.root->c[1]->setc(T.build(1,n),0); T.root->c[1]->push_up(); T.root->push_up();
    88 }
    89 int main(){
    90     init();
    91     while(m--){
    92         char c; int x,y;
    93         read(c); read(x);
    94         if(c=='Q'){ read(y); printf("%d
    ",bsearch(x,y)); }
    95         else if(c=='R') T.chg(read(c)-'a'+1,x);
    96         else T.ins(read(c)-'a'+1,x);
    97     }
    98     return 0;
    99 }
    View Code
  • 相关阅读:
    UVALive 4329 Ping pong
    面试题——设计一个程序:运行报错Stack Overflow Error
    MongoDB 主从复制小实验
    我总结的18个非常好用的vim指令
    php性能优化
    error LNK2019: unresolved external symbol / error LNK2001: 无法解析的外部符号
    CopyU!v2 已经收录到腾讯软件管家!
    HDU 1498 50 years, 50 colors (行列匹配+最小顶点覆盖)
    汉语-词语-庸俗:百科
    汉语-成语-见笑大方:百科
  • 原文地址:https://www.cnblogs.com/Sunnie69/p/5602162.html
Copyright © 2020-2023  润新知