zoukankan      html  css  js  c++  java
  • 【bzoj1014】[JSOI2008]火星人prefix

    1014: [JSOI2008]火星人prefix

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 6031  Solved: 1917
    [Submit][Status][Discuss]

    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个数据,没有插入操作。

    【题解】

    用splay维护字符串,把一段子串用哈希值表示,两个长度相同的子串如果哈希值相同,那么它们就相同。

    建树时每棵子树的哈希值集中在根节点上,即h[x]=(h[left[x]]+v[x]*p[size[left]]+h[r]*p[size[left]+1])%mod

    查询时二分一个答案,然后验证。

    那么如何找到子串的哈希值呢?

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

    吐槽:这题交了很多遍,都是RE,然后我才知道BZOJ上用cin会RE......

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstdlib>
      4 #include<cstring>
      5 #include<cmath>
      6 #include<ctime>
      7 #include<algorithm>
      8 using namespace std;
      9 #define MAXN 150010
     10 #define ll long long
     11 #define mod 9875321
     12 int n,m,rt,sz,p[MAXN],c[MAXN][2],fa[MAXN],size[MAXN],h[MAXN],v[MAXN];
     13 char ch[MAXN];
     14 namespace INIT
     15 {
     16 inline int read()
     17 {
     18     int x=0,f=1;  char ch=getchar();
     19     while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getchar();}
     20     while(isdigit(ch))  {x=x*10+ch-'0';  ch=getchar();}
     21     return x*f;
     22 }
     23 }using namespace INIT;
     24 namespace SPLAY
     25 {
     26 void updata(int x)
     27 {
     28     int l=c[x][0],r=c[x][1];
     29     size[x]=size[l]+size[r]+1;
     30     h[x]=h[l]+(ll)v[x]*p[size[l]]%mod+(ll)p[size[l]+1]*h[r]%mod;
     31     h[x]%=mod;
     32 }
     33 void rotate(int x,int &k)
     34 {
     35     int y=fa[x],z=fa[y],l,r;
     36     if(c[y][0]==x)  l=0;  else l=1;  r=l^1;
     37     if(y==k)  k=x;
     38     else {if(c[z][0]==y)  c[z][0]=x;  else c[z][1]=x;}
     39     fa[x]=z;  fa[y]=x;  fa[c[x][r]]=y;
     40     c[y][l]=c[x][r];  c[x][r]=y;
     41     updata(y);  updata(x);
     42 }
     43 void Splay(int x,int &k)
     44 {
     45     while(x!=k)
     46     {
     47         int y=fa[x],z=fa[y];
     48         if(y!=k)
     49         {
     50             if((c[y][0]==x)^(c[z][0]==y))  rotate(x,k);
     51             else rotate(y,k);
     52         }
     53         rotate(x,k);
     54     }
     55 }
     56 void build(int k,int l,int r)
     57 {
     58     if(l>r)  return;
     59     if(l==r)
     60     {
     61         v[l]=h[l]=ch[l]-'a'+1;
     62         fa[l]=k;  size[l]=1;
     63         if(l<k)  c[k][0]=l;
     64         else c[k][1]=l;
     65         return;
     66     }
     67     int mid=(l+r)/2;
     68     build(mid,l,mid-1);  build(mid,mid+1,r);
     69     v[mid]=ch[mid]-'a'+1; fa[mid]=k;  updata(mid);
     70     if(mid<k)  c[k][0]=mid;
     71     else c[k][1]=mid;
     72 }
     73 int find(int k,int rank)
     74 {
     75     int l=c[k][0],r=c[k][1];
     76     if(size[l]+1==rank)  return k;
     77     else if(size[l]>=rank)  return find(l,rank);
     78     else return find(r,rank-size[l]-1);
     79 }
     80 int check(int k,int val)
     81 {
     82     int x=find(rt,k),y=find(rt,k+val+1);
     83     Splay(x,rt);  Splay(y,c[x][1]);
     84     int z=c[y][0];
     85     return h[z];
     86 }
     87 int ask(int x,int y)
     88 {
     89     int l=1,r=min(sz-x,sz-y)-1,ans=0;
     90     while(l<=r)
     91     {
     92         int mid=(l+r)/2;
     93         if(check(x,mid)==check(y,mid))   {l=mid+1;  ans=mid;}
     94         else r=mid-1;
     95     }
     96     return ans;
     97 }
     98 void insert(int k,int val)
     99 {
    100     int x=find(rt,k+1),y=find(rt,k+2);
    101     Splay(x,rt);  Splay(y,c[x][1]);
    102     int z=++sz;  c[y][0]=z;  fa[z]=y;  v[z]=val;
    103     updata(z);  updata(y);  updata(x);
    104 }
    105 }using namespace SPLAY;
    106 int main()
    107 {
    108     //freopen("cin.in","r",stdin);
    109     //freopen("cout.out","w",stdout);
    110     scanf("%s",ch+2);
    111     n=strlen(ch+2);   p[0]=1;
    112     for(int i=1;i<=MAXN;i++)  p[i]=p[i-1]*27%mod;
    113     build(0,1,n+2);  rt=(n+3)/2;  sz=n+2;
    114     m=read();   int x,y;
    115     char s[2],d[2];
    116     for(int i=1;i<=m;i++)
    117     {
    118         scanf("%s",s+1);  x=read();
    119         if(s[1]=='Q')  {y=read();  printf("%d
    ",ask(x,y));}
    120         if(s[1]=='R')  {scanf("%s",d+1);  x=find(rt,x+1);  Splay(x,rt);  v[rt]=d[1]-'a'+1;  updata(rt);}
    121         if(s[1]=='I')  {scanf("%s",d+1);  insert(x,d[1]-'a'+1);}
    122     }
    123     return 0;
    124 }

    附makedata程序(博主很良心,知道你会wa):

     1 #include<iostream>
     2 using namespace std;
     3 char ch[5]={'Q','R','I'};
     4 int main()
     5 {
     6     freopen("cin.in","w",stdout);
     7     srand(time(NULL));
     8     int n=100;
     9     for(int i=1;i<=n;i++)  printf("%c",(char)('a'+rand()%26));
    10     printf("
    ");
    11     int m=1500;
    12     printf("%d
    ",m);
    13     for(int i=1;i<=m;i++)
    14     {
    15         char f=ch[rand()%3];
    16         if(f=='Q')  {printf("%c %d %d
    ",f,rand()%n+1,rand()%n+1);}
    17         if(f=='R')  {printf("%c %d %c
    ",f,rand()%n+1,(char)('a'+rand()%26));}
    18         if(f=='I')  {printf("%c %d %c
    ",f,rand()%n+1,(char)('a'+rand()%26));}
    19     }
    20     return 0;
    21 }
  • 相关阅读:
    iOS企业证书开发的APP证书过期时间监控
    事件冒泡,事件捕获
    倒计时
    获取多个div,点击第几个,显示第几个
    js继承
    javascript基础知识总结
    大型web系统高效应用方法(转载)
    数据库(内联,外联,交叉联)
    .net零碎基础知识点不完全小结
    C#的内存管理:堆、栈、托管堆与指针(转)
  • 原文地址:https://www.cnblogs.com/chty/p/5881158.html
Copyright © 2011-2022 走看看