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(n\log^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\n",ans=max(ask(RT[y],1,100000,x,y),cal(T[y],1,100000,x)-x+1));
    }
  }
  return 0;
}

  

时间: 2024-08-06 03:40:03

BZOJ4963 : String的相关文章

C# 引用类型之特例string

在C#编程的时候经常会使用字符串(string)类型,它也是引用类型,但是处处都不作为引用的用法来使用,实属特例,下来我一一罗列出来,供自己记忆方便: 1)字符串的直接赋值:本身字符串就是引用类型,应该使用  new 对象方法一个实例,但是微软为了方便大家,可以直接定义字符串变量 并且赋值操作,例如: string a = "我的中国心"; ,这样只是简化我们的操作: 2)一个字符串赋值给另一个字符串变量:正常的引用类型会将两个引用变量指向同一个地址,但是一个字符串变量赋值给另一个字符

C++ String 及其与char[]的比较

在学习C++之前  一般都是学过了C语言了 在C语言中   我们对字符串进行保存操作  使用的是char[] 但是在C++中    string比char[]的使用更为频繁  常见    下面稍微讲一下我对于string的认知 1.与其他的标准库类型一样   用户程序需要使用String类型对象  就必须包含相关的头文件   (为了编写方便   需要提供合适的using声明) #include <string> using std::string; 2.string对象的定义与初始化 stri

java String 类 基础笔记

字符串是一个特殊的对象. 字符串一旦初始化就不可以被改变. String s = "abc";//存放于字符串常量池,产生1个对象 String s1=new String("abc");//堆内存中new创建了一个String对象,产生2个对象 String类中的equals比较字符串中的内容. 常用方法: 一:获取 1.获取字符串中字符的个数(长度):length();方法. 2.根据位置获取字符:charAt(int index); 3.根据字符获取在字符串中

The constructor ClassPathXmlApplicationContext(String) refers to the missing type BeansException

"The constructor ClassPathXmlApplicationContext(String) refers to the missing type BeansException" "构造函数ClassPathXmlApplicationContext(字符串)是指缺失类型BeansException" 出现错误的原因:jar没有正确引入,即使表面上你能import包. import org.junit.Test; import org.spring

float类型如何转换为string类型

在一些很大的float类型的地方会用科学记数法表示,这个时候如果想完整记录下来,还是得转字符串,这里书写一个float类型转string类型的方法 <?php function float_to_string($float=0) { if(stripos($float, "e")!==false) { $tmp = explode("e",strtolower($float)); $float=bcmul($tmp[0], bcpow(10, $tmp[1])

JAVA: String详解

String 类用来存储字符串 ,是不可变的. 1. 基本数据类型,也称原始数据类型.byte,short,char,int,long,float,double,boolean 他们之间的比较,应用双等号(==),比较的是他们的值. 2. 复合数据类型(类) 当他们用(==)进行比较的时候,比较的是他们在内存中的存放地址,所以,除非是同一个new出来的对象,他们的比较后的结果为true,否则比较后结果为false.用 str.equals(str2) 方法来比较字符串的值是否相等. 3. len

TypeError: string indices must be integers, not str

1. TypeError: string indices must be integers, not str 字符串类型取第index个字符的时候,应该传入int而不是str.如 view source print? 1 a='abcdef' 2 print a[0] 3 #而不是 print a['0'] 更常见的情况是把一个string当成了字典在使用 :should_be_dict_but_string['id'] .这样的错误

to String()用法

toString()的使用: * * 1.java.lang.Object类中toString()定义如下: * public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); } * * 2. 当我们打印一个对象的引用时,实际上就是调用了其toString() * * 3. 像String.Date.File.包装类等重写了Object类中的toString

186. Reverse Words in a String II

https://leetcode.com/problems/reverse-words-in-a-string-ii/#/description Given an input string, reverse the string word by word. A word is defined as a sequence of non-space characters. The input string does not contain leading or trailing spaces and