• BZOJ4963 : String


    用SAM支持往末尾在线添加字符的功能。

    设$f[i][j]$表示右端点为i的每个左端点的答案,那么当$i$变为$i+1$时,在SAM的parent链形成的树中会新增一个叶子$p$。

    对于每个节点,维护它最后一次出现的位置的右端点$v$,那么加入$p$的时候,需要把它到根路径上所有节点的$v$都改为$i+1$,而它们之前的$v$值就是它们倒数第二次出现的位置,可以用$v$来更新答案。

    用LCT维护parent树,那么赋值为一种新的颜色可以用access操作实现,经过的每条实链的$v$值都相同。

    而在这条实链中,找出最短和最长的子串,那么长度介于它们之间的子串均以$v$结尾作为倒数第二次出现。

    对于$f[i+1][]$来说,等价于一段前缀区间取最大值,中间一段贡献一个等差数列,线段树维护即可。

    为了在线回答询问,将线段树可持久化即可。

    时间复杂度$O(nlog^2n)$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N=100010,M=N<<1,E=20000000;
    int n,m,i,op,x,y,ans;char a[N];
    int tot=1,last=1,pre[M],son[M][26],ml[M];
    int T[N],cnt,l[E],r[E],v[E],RT[N],TOT,L[E],R[E],V[E];
    inline void umin(int&a,int b){ml[a]>ml[b]?(a=b):0;}
    inline void umax(int&a,int b){a<b?(a=b):0;}
    int change(int x,int a,int b,int c,int d,int p){
      int y=++cnt;
      l[y]=l[x],r[y]=r[x],v[y]=v[x];
      if(c<=a&&b<=d){
        umax(v[y],p);
        return y;
      }
      int mid=(a+b)>>1;
      if(c<=mid)l[y]=change(l[x],a,mid,c,d,p);
      if(d>mid)r[y]=change(r[x],mid+1,b,c,d,p);
      return y;
    }
    int cal(int x,int a,int b,int c){
      if(a==b)return v[x];
      int mid=(a+b)>>1;
      return max(v[x],c<=mid?cal(l[x],a,mid,c):cal(r[x],mid+1,b,c));
    }
    int ins(int x,int a,int b,int c,int d){
      int y=++TOT;
      V[y]=max(V[x],d);
      if(a==b)return y;
      int mid=(a+b)>>1;
      if(c<=mid)L[y]=ins(L[x],a,mid,c,d),R[y]=R[x];else L[y]=L[x],R[y]=ins(R[x],mid+1,b,c,d);
      return y;
    }
    int ask(int x,int a,int b,int c,int d){
      if(c<=a&&b<=d)return V[x];
      int mid=(a+b)>>1,t=0;
      if(c<=mid)t=ask(L[x],a,mid,c,d);
      if(d>mid)umax(t,ask(R[x],mid+1,b,c,d));
      return t;
    }
    inline void modify(int v,int l,int r){
      if(!v||l>r)return;
      RT[n]=ins(RT[n],1,100000,v-r+1,r);
      T[n]=change(T[n],1,100000,v-r+1,v-l+1,v);
    }
    namespace LCT{
    int f[M],son[M][2],vis[M],tag[M],mi[M],ma[M],a[M];
    inline bool isroot(int x){return !f[x]||son[f[x]][0]!=x&&son[f[x]][1]!=x;}
    inline void tag1(int x,int p){
      if(!x)return;
      umax(vis[x],p),umax(tag[x],p);
    }
    inline void pb(int x){if(tag[x])tag1(son[x][0],tag[x]),tag1(son[x][1],tag[x]),tag[x]=0;}
    inline void up(int x){
      mi[x]=x,ma[x]=ml[x];
      if(son[x][0])umin(mi[x],mi[son[x][0]]),umax(ma[x],ma[son[x][0]]);
      if(son[x][1])umin(mi[x],mi[son[x][1]]),umax(ma[x],ma[son[x][1]]);
    }
    inline void rotate(int x){
      int y=f[x],w=son[y][1]==x;
      son[y][w]=son[x][w^1];
      if(son[x][w^1])f[son[x][w^1]]=y;
      if(f[y]){
        int z=f[y];
        if(son[z][0]==y)son[z][0]=x;else if(son[z][1]==y)son[z][1]=x;
      }
      f[x]=f[y];f[y]=x;son[x][w^1]=y;up(y);
    }
    inline void splay(int x){
      int s=1,i=x,y;a[1]=i;
      while(!isroot(i))a[++s]=i=f[i];
      while(s)pb(a[s--]);
      while(!isroot(x)){
        y=f[x];
        if(!isroot(y)){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
        rotate(x);
      }
      up(x);
    }
    inline void cut(int x){
      splay(x);
      if(son[x][0])f[son[x][0]]=f[x];
      son[x][0]=0;
      up(x);
    }
    inline void access(int x){
      for(int y=0;x;y=x,x=f[x]){
        splay(x);
        son[x][1]=0;
        up(x);
        modify(vis[x],ml[pre[mi[x]]]+1,ma[x]);
        tag1(x,n);
        son[x][1]=y;
        up(x);
      }
    }
    }
    inline void ext(int w){
      ++n;
      RT[n]=RT[n-1],T[n]=T[n-1];
      int p=++tot,x=last,r,q;
      for(ml[last=p]=ml[x]+1;x&&!son[x][w];x=pre[x])son[x][w]=p;
      if(!x)pre[p]=1;
      else if(ml[x]+1==ml[q=son[x][w]])pre[p]=q;
      else{
        pre[r=++tot]=pre[q];memcpy(son[r],son[q],sizeof son[r]);
        ml[r]=ml[x]+1;
        LCT::up(r);
        LCT::splay(q);
        LCT::vis[r]=LCT::vis[q];
        LCT::f[r]=pre[q];
        LCT::cut(q);
        LCT::f[q]=r;
        pre[p]=pre[q]=r;
        for(;x&&son[x][w]==q;x=pre[x])son[x][w]=r;
      }
      LCT::up(p);
      LCT::f[p]=pre[p];
      LCT::access(p);
    }
    int main(){
      scanf("%s",a+1);
      m=strlen(a+1);
      for(i=1;i<=m;i++)ext(a[i]-'a');
      scanf("%d",&m);
      while(m--){
        scanf("%d",&op);
        if(op==1){
          scanf("%s",a);
          x=a[0]-'a';
          x=((x+ans)%26+26)%26;
          ext(x);
        }else{
          scanf("%d%d",&x,&y);
          x=((x-1+ans)%n+n)%n+1;
          y=((y-1+ans)%n+n)%n+1;
          if(x>y)swap(x,y);
          printf("%d
    ",ans=max(ask(RT[y],1,100000,x,y),cal(T[y],1,100000,x)-x+1));
        }
      }
      return 0;
    }
    

      

  • 相关阅读:
    StringBuffer与Stringbuilder
    String与其他类型的转换
    创建多进程的方法
    8.进程
    克隆虚拟机
    初探12306售票算法(二)-java代码实践
    初探12306售票算法(一)- 理论
    手机上mcd程序耗电异常问题相关
    vue版app上下拉加载
    css基础
  • 原文地址:https://www.cnblogs.com/clrs97/p/7421126.html
Copyright © 2020-2023  润新知