• bzoj 1014 [JSOI2008]火星人prefix


    [JSOI2008]火星人prefix

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 8322  Solved: 2645
    [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个数据,没有插入操作。

    题解,插入,删除这些操作应该是平衡树的基本操作,如何求最长公共前缀呢,就hash+二分判断即可。

      1 #include<cstring>
      2 #include<cmath>
      3 #include<iostream>
      4 #include<algorithm>
      5 #include<cstdio>
      6 
      7 #define mod 9875321
      8 #define ll long long
      9 #define N 150007
     10 using namespace std;
     11 inline int read()
     12 {
     13     int x=0,f=1;char ch=getchar();
     14     while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
     15     while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
     16     return x*f;
     17 }
     18 
     19 int n,m,rt,sz;
     20 int a[N];
     21 int c[N][2],fa[N],siz[N],val[N];
     22 int v[N],h[N],p[N],id[N];
     23 char ch[N];
     24 
     25 void update(int k)
     26 {
     27     int l=c[k][0],r=c[k][1];
     28     siz[k]=siz[l]+siz[r]+1;
     29     h[k]=h[l]+(ll)v[k]*p[siz[l]]%mod+(ll)p[siz[l]+1]*h[r]%mod;
     30     h[k]%=mod; //h表示这棵子树的hash值 
     31 }
     32 void rotate(int x,int &k)
     33 {
     34     int y=fa[x],z=fa[y],l,r;
     35     if (c[y][0]==x)l=0;else l=1;r=l^1;
     36     if (y==k) k=x;
     37     else
     38     {
     39         if (c[z][0]==y) c[z][0]=x;
     40         else c[z][1]=x;
     41     }
     42     fa[x]=z,fa[y]=x,fa[c[x][r]]=y;
     43     c[y][l]=c[x][r],c[x][r]=y;
     44     update(y),update(x);
     45 }
     46 void splay(int x,int &p)
     47 {
     48     while(x!=p)
     49     {
     50         int y=fa[x],z=fa[y];
     51         if (y!=p)
     52         {
     53             if (c[y][0]==x^c[z][0]==y) rotate(x,p);
     54             else rotate(y,p);
     55         }
     56         rotate(x,p);
     57     }
     58 }
     59 int find(int k,int rk)
     60 {
     61     int l=c[k][0],r=c[k][1];
     62     if(siz[l]+1==rk)return k;
     63     else if(siz[l]>=rk)return find(l,rk);
     64     else return find(r,rk-siz[l]-1);
     65 }
     66 void ins(int k,int val)
     67 {
     68     int x=find(rt,k+1),y=find(rt,k+2);
     69     splay(x,rt);splay(y,c[x][1]);
     70     int z=++sz;c[y][0]=z;fa[z]=y;v[z]=val;
     71     update(z);update(y);update(x);
     72 }
     73 int query(int k,int val)
     74 {
     75     int x=find(rt,k),y=find(rt,k+val+1);
     76     splay(x,rt);splay(y,c[x][1]);
     77     int z=c[y][0];
     78     return h[z];//应该比较好理解的吧,旋转出来,把那一段旋转出来,最后那个点就是代表这一段的hash值。 
     79 }
     80 int solve(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 void build(int l,int r,int f)
     92 {
     93     if(l>r)return;
     94     int now=id[l],last=id[f];
     95     if(l==r)
     96     {
     97         v[now]=h[now]=ch[l]-'a'+1;
     98         fa[now]=last;siz[now]=1;
     99         if(l<f)c[last][0]=now;
    100         else c[last][1]=now;
    101         return;
    102     }
    103     int mid=(l+r)>>1;now=id[mid];
    104     build(l,mid-1,mid);build(mid+1,r,mid);
    105     v[now]=ch[mid]-'a'+1;fa[now]=last;update(now);
    106     if(mid<f)c[last][0]=now;
    107     else c[last][1]=now;
    108 }
    109 void init()
    110 {
    111     scanf("%s",ch+2);
    112     n=strlen(ch+2);
    113     p[0]=1;
    114     for (int i=1;i<N;i++)
    115         p[i]=p[i-1]*27%mod;
    116     for (int i=1;i<=n+2;i++)
    117         id[i]=i;
    118     build(1,n+2,0);//这类问题不要忘了放开头,结尾两个哨兵。 
    119     sz=n+2,rt=(n+3)>>1;
    120 }
    121 int main()
    122 {
    123     init(),m=read();
    124     while(m--)
    125     {
    126         char s[2];scanf("%s",s);
    127         if (s[0]=='Q')
    128         {
    129             int x=read(),y=read();
    130             printf("%d
    ",solve(x,y));
    131         }
    132         else if (s[0]=='R')
    133         {
    134             int x=read();char zhi[2];scanf("%s",zhi);
    135             x=find(rt,x+1);splay(x,rt);
    136             v[rt]=zhi[0]-'a'+1;
    137             update(rt);//修改是更加简单的。 
    138         }
    139         else 
    140         {
    141             int x=read();char zhi[2];scanf("%s",zhi);
    142             ins(x,zhi[0]-'a'+1);
    143         }
    144     }
    145 }
  • 相关阅读:
    [转载]setup factory使用方法
    MFC中调用WPF教程
    Reduce the Number of SQL Statements
    Library Cache Hit Ratio
    Seconds in wait
    PX Deq: Execute Reply等待事件
    RoundTrip Time
    Changing an Init.ora Parameter
    PX qref latch等待事件
    提高DBWR进程的吞吐量
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/8072034.html
Copyright © 2020-2023  润新知