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

    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函数的值。

    Input

      第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。接下来的M行,每行描述一个操作。操
    作有3种,如下所示
    1、询问。语法:Qxy,x,y均为正整数。功能:计算LCQ(x,y)限制:1<=x,y<=当前字符串长度。
    2、修改。语法:Rxd,x是正整数,d是字符。功能:将字符串中第x个数修改为字符d。限制:x不超过当前字
    符串长度。
    3、插入:语法:Ixd,x是非负整数,d是字符。功能:在字符串第x个字符之后插入字符d,如果x=0,则在字
    符串开头插入。限制:x不超过当前字符串长度

    Output

      对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。

    Sample Input

    madamimadam
    7
    Q 1 7
    Q 4 8
    Q 10 11
    R 3 a
    Q 1 7
    I 10 a
    Q 2 11

    Sample Output

    5
    1
    0
    2
    1

    HINT

    1、所有字符串自始至终都只有小写字母构成。

    2、M<=150,000

    3、字符串长度L自始至终都满足L<=100,000

    4、询问操作的个数不超过10,000个。

    对于第1,2个数据,字符串长度自始至终都不超过1,000

    对于第3,4,5个数据,没有插入操作。

    Source

    今天终于把这个名为"火星人”的坑给填了。。。

    这道题曾经对刚打完营业额统计的我产生了巨大的心理阴影。。。

    直到昨天晚自习无聊看刘汝佳白书,陡然发现有一个名叫魔法珠宝的题勾起了我童年的回忆。。。

    对于字符串的多次修改,后缀数组是不能胜任的(蒟蒻并不会),看到插入,修改。。splay就能排上用场了。。。

    求LCP的话用二分+哈希可以在logn的时间判断,就是二分一个长度用哈希值判断两个串是否相等。。。

    不得不说哈希真的是解决字符串问题的万能方法。。。O(1)判断啊,开玩笑。。。。

    splay的作用就是用来维护这个字符串的。。。其中每个节点相当与掌握了他所管辖区间的一段的哈希值。。。。

    update的时候再由左右儿子的哈希值重新计算,这就需要再维护一个子树大小了。。。(算哈希用)。。。。

    就像这样:hsh[x]=hsh[left[x]]+v[x]*pre[size[left]]+hsh[r]*pre[size[left]+1]。。。。。

    每次询问相当于是要提取一段的哈希值。。。

    对于询问,对于需要的一个子串首先找到子串的首字母,把它伸展到根,然后找到子串的尾字母的下一个字母,把它伸展到根的右儿子,那么根的右儿子的左儿子的哈希值就是答案。

    貌似叶大佬和俊琦下了一堆特判。。。我在前面插了一个$,后面插了$一个貌似就没事了???

    对于插入操作:

    把插入位置splay到根,下一位splay到根的右子树,然后直接往根的右子树的左子树上插就可以了,直接在根结点上修改再update()。

    修改操作就没什么好说的了。。。直接splay到根,修改再update();

    不得不说这个题真的有点码,关键是难调。。。splay天旋地转调个鬼。。。

    Orz 这是jesseliu612大佬的splay入门题。。。。

    今天长见识了,原来是不能定hash这个数组的。。。CE。。。

    貌似跑得贼慢。。。9800ms踩线过

      1 // MADE BY QT666
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cmath>
      5 #include<iostream>
      6 #include<queue>
      7 #include<set>
      8 #include<cstdlib>
      9 #include<cstring>
     10 #include<string>
     11 #include<ctime>
     12 #define lson num<<1
     13 #define rson num<<1|1
     14 #define int long long
     15 using namespace std;
     16 typedef long long ll;
     17 const int N=150005;
     18 const int mod=23333333;
     19 int size[N],v[N],hsh[N],pre[N];
     20 int c[N][2],fa[N];
     21 int n,m,rt,sz;
     22 char ch[N];
     23 int gi()
     24 {
     25   int x=0,flag=1;
     26   char ch=getchar();
     27   while(ch<'0'||ch>'9'){if(ch=='-') flag=-1;ch=getchar();}
     28   while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
     29   return x*flag;
     30 }
     31 inline void update(int x)
     32 {
     33     int l=c[x][0],r=c[x][1];
     34     size[x]=size[l]+size[r]+1;
     35     hsh[x]=hsh[l]+v[x]*pre[size[l]]+pre[size[l]+1]*hsh[r];
     36 }                         
     37 inline void rotate(int x,int &k)
     38 {
     39     int y=fa[x],z=fa[y],l,r;
     40     if(c[y][0]==x)l=0;else l=1;r=l^1;
     41     if(y==k) k=x;
     42     else{if(c[z][0]==y) c[z][0]=x;else c[z][1]=x;}
     43     fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
     44     c[y][l]=c[x][r],c[x][r]=y;
     45     update(y);update(x);
     46 }
     47 inline void splay(int x,int &k)
     48 {
     49   while(x!=k)
     50    {
     51       int y=fa[x],z=fa[y];
     52       if(y!=k)
     53       {
     54           if((c[y][0]==x)^(c[z][0]==y)) rotate(x,k);
     55           else rotate(y,k);
     56        }
     57       rotate(x,k);
     58    }
     59 }
     60 inline int find(int x,int y)
     61 {
     62     int l=c[x][0],r=c[x][1];
     63     if(size[l]+1==y) return x;
     64     else if(size[l]>=y) return find(l,y);
     65     else return find(r,y-size[l]-1);
     66 }
     67 inline int query(int k,int len)
     68 {
     69     int x=find(rt,k),y=find(rt,k+len+1);
     70     splay(x,rt);splay(y,c[x][1]);
     71     return hsh[c[y][0]];
     72 }
     73 inline void insert(int k,int val)
     74 {
     75     int x=find(rt,k+1),y=find(rt,k+2);
     76     splay(x,rt);splay(y,c[x][1]);
     77     int z=++sz;c[y][0]=z;fa[z]=y;v[z]=val;
     78     update(z);update(y);update(x);
     79 }
     80 inline int work(int x,int y)
     81 {
     82     int l=1,r=min(sz-x,sz-y)-1,ans=0;
     83     while(l<=r)
     84       {
     85           int mid=(l+r)>>1;
     86           if(query(x,mid)==query(y,mid)) l=mid+1,ans=mid;
     87           else r=mid-1;
     88       }
     89     return ans;
     90 }
     91 inline void build(int l,int r,int f)
     92 {
     93    if(l>r)return;
     94    int mid=(l+r)>>1;
     95    if(l==r)
     96     {
     97         v[l]=hsh[l]=ch[l]-'a'+1;size[l]=1;
     98     }
     99     else build(l,mid-1,mid),build(mid+1,r,mid);
    100     v[mid]=ch[mid]-'a'+1;fa[mid]=f;update(mid);
    101     if(mid<f)c[f][0]=mid;
    102     else c[f][1]=mid;
    103  }
    104 main()
    105 {
    106     scanf("%s",ch+2);
    107     n=strlen(ch+2);ch[1]='$',ch[n+2]='$';
    108     pre[0]=1;for(int i=1;i<=N-1;i++) pre[i]=pre[i-1]*27;
    109     build(1,n+2,0);sz=n+2;rt=(n+3)>>1;
    110     m=gi();
    111     int x,y;char s[2],d[2];
    112     for(int i=1;i<=m;i++)
    113     {
    114         scanf("%s",s+1);
    115         x=gi();
    116         if(s[1])
    117         {
    118             if(s[1]=='Q') y=gi(),printf("%lld
    ",work(x,y));
    119             else if(s[1]=='R')
    120             {
    121              scanf("%s",d+1);x=find(rt,x+1);splay(x,rt);
    122              v[rt]=d[1]-'a'+1;update(rt);
    123             }
    124             else if(s[1]=='I') {scanf("%s",d+1);insert(x,d[1]-'a'+1);}
    125         }
    126     }
    127     return 0;
    128 }
  • 相关阅读:
    js搜索输入关键词
    pc端,自适应屏幕分辨率
    js获取锚点名称 #
    yourphp读取分类名称{$Categorys[$r[catid]]['catname']}
    收缩菜单 css变样
    ajax成功跨域_自己写的
    json 是个什么东西?
    json_encode详解,转义
    跨域代码 手机号码
    php json_decode
  • 原文地址:https://www.cnblogs.com/qt666/p/6494586.html
Copyright © 2011-2022 走看看