将初始字符串和添加的字符串按照添加顺序 逆序 拼成一个大串S,那么一个串可以被表示成S[l1~r1]+S[l2~r2]…
我们维护height[i]=LCP(s[i-1],s[i]),L~R的LCP=min{ height[L+1~R] }
每次在L~R前面添加一个串T时,L+1~R的height区间加|T|,height[L]和height[R+1]要重新计算,二分加hash计算
考虑怎么计算hash,离线所有操作,将一个对L~R的加操作变成L处加入,R+1处删除,1~n扫一遍所有串,处理出每个串最终在S串的哪些位置取值,然后按时间顺序处理询问,就相当于问线段树上某个坐标往右k个位置的hash值
code:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const int maxn = 51000;
const int maxp = 610000;
const int maxd = 20;
const int base = 31;
int BASE[maxp];
int n,m,N;
int lr[maxn][2],op[maxn][5];
vector<int>Add[maxn],Del[maxn];
string str[maxn],add[maxn];
char S[maxp],ss[10];
struct segment
{
int seg[maxp<<2],flag[maxp<<2];
int lx,rx,c;
void pushdown(const int x)
{
if(!flag[x]) return;
int fl=flag[x]; flag[x]=0;
int lc=x<<1,rc=lc|1;
seg[lc]+=fl,seg[rc]+=fl;
flag[lc]+=fl,flag[rc]+=fl;
}
void upd(const int x,const int l,const int r)
{
if(rxreturn;
if(lx<=l&&r<=rx) { seg[x]+=c,flag[x]+=c;return; }
pushdown(x);
int mid=l+r>>1;
upd(x<<1,l,mid),upd(x<<1|1,mid+1,r);
seg[x]=min(seg[x<<1],seg[x<<1|1]);
}
int query(const int x,const int l,const int r)
{
if(rxreturn N+1;
if(lx<=l&&r<=rx) return seg[x];
pushdown(x);
int mid=l+r>>1;
return min(query(x<<1,l,mid),query(x<<1|1,mid+1,r));
}
}height,L;
struct Cover
{
int seg[maxn<<2];
int lx,rx,loc,c;
void cov(const int x,const int l,const int r)
{
if(rxreturn;
if(lx<=l&&r<=rx) { seg[x]=c; return; }
if(seg[x]) seg[x<<1]=seg[x<<1|1]=seg[x],seg[x]=0;
int mid=l+r>>1;
cov(x<<1,l,mid); cov(x<<1|1,mid+1,r);
}
int query(const int x,const int l,const int r)
{
if(l==r) return seg[x];
if(seg[x]) seg[x<<1]=seg[x<<1|1]=seg[x],seg[x]=0;
int mid=l+r>>1;
if(loc<=mid) return query(x<<1,l,mid);
else return query(x<<1|1,mid+1,r);
}
}Left;
struct Seg
{
int lc[maxp*maxd],rc[maxp*maxd],h[maxp*maxd],len[maxp*maxd];
int lx,rx,cnt;
void pushup(int x)
{
int ls=lc[x],rs=rc[x];
len[x]=len[ls]+len[rs];
h[x]=h[ls]+h[rs]*BASE[len[ls]];
}
void build(int &x,const int l,const int r)
{
if(!x) x=++cnt;
if(l==r) { len[x]=1,h[x]=S[l]-'a'+1; return; }
int mid=l+r>>1;
build(lc[x],l,mid); build(rc[x],mid+1,r);
pushup(x);
}
void merge(int &x,const int &y)
{
if(!y) return;
if(!x) { x=y; return; }
++cnt; lc[cnt]=lc[x],rc[cnt]=rc[x]; x=cnt;
merge(lc[x],lc[y]),merge(rc[x],rc[y]);
pushup(x);
}
void split(int &x,const int y,const int l,const int r)
{
if(rxreturn;
if(lx<=l&&r<=rx) { x=y;return; }
x=++cnt;
int mid=l+r>>1;
split(lc[x],lc[y],l,mid); split(rc[x],rc[y],mid+1,r);
pushup(x);
}
void dec(int &x,const int l,const int r)
{
if(rxreturn;
if(lx<=l&&r<=rx) { x=0; return; }
++cnt; lc[cnt]=lc[x],rc[cnt]=rc[x]; x=cnt;
int mid=l+r>>1;
dec(lc[x],l,mid); dec(rc[x],mid+1,r);
if(!lc[x]&&!rc[x]) x=0;
if(x) pushup(x);
}
int ql,ul;
int query(int x,const int l,const int r)
{
if(rxreturn 0;
if(lx<=l&&r<=rx&&ql+len[x]<=ul) { ql+=len[x]; return h[x]; }
int mid=l+r>>1;
int nl=ql,q1=query(lc[x],l,mid); nl=ql-nl;
int q2=query(rc[x],mid+1,r);
return q1+q2*BASE[nl];
}
}seg; int root[maxn];
void BuildSeg()
{
for(int i=m;i>=1;i--) if(!op[i][0])
{
int il=add[i].size();
op[i][3]=N+1; op[i][4]=N+il;
for(int j=0;jfor(int i=1;i<=n;i++)
{
int il=str[i].size();
lr[i][0]=N+1,lr[i][1]=N+il;
for(int j=0;j0]; Left.cov(1,1,n);
L.lx=L.rx=i; L.c=il; L.upd(1,1,n);
if(i>1)
{
il=min(il,(int)str[i-1].size()); int hi=0;
while(hi1][hi]==str[i][hi]) hi++;
height.lx=height.rx=i; height.c=hi; height.upd(1,1,n);
}
}
seg.build(root[0],1,N);
for(int i=1;i<=m;i++) if(!op[i][0])
{
Add[op[i][1]].push_back(i);
if(op[i][2]2]+1].push_back(i);
}
for(int i=1;i<=n;i++)
{
seg.lx=lr[i][0],seg.rx=lr[i][1],seg.split(root[i],root[0],1,N);
if(i>1)
{
seg.merge(root[i],root[i-1]);
seg.lx=lr[i-1][0],seg.rx=lr[i-1][1],seg.dec(root[i],1,N);
}
for(int j=0;jint k=Add[i][j]; seg.lx=op[k][3],seg.rx=op[k][4];
k=0; seg.split(k,root[0],1,N);
seg.merge(root[i],k);
}
for(int j=0;jint k=Del[i][j]; seg.lx=op[k][3],seg.rx=op[k][4];
seg.dec(root[i],1,N);
}
}
}
bool judge(int i,int mid,int l1,int r1,int l2,int r2)
{
seg.lx=l1,seg.rx=r1; seg.ql=0,seg.ul=mid; int h1=seg.query(root[i],1,N);
seg.lx=l2,seg.rx=r2; seg.ql=0,seg.ul=mid; int h2=seg.query(root[i+1],1,N);
return h1==h2;
}
int cal(int i)
{
int u=N;
L.lx=L.rx=i; u=min(u,L.query(1,1,n));
L.lx=L.rx=i+1; u=min(u,L.query(1,1,n));
int l1,r1,l2,r2;
Left.loc=i; l1=Left.query(1,1,n);
Left.loc=i+1; l2=Left.query(1,1,n);
r1=lr[i][1],r2=lr[i+1][1];
int l=1,r=u;
while(l<=r)
{
int mid=l+r>>1;
if(judge(i,mid,l1,r1,l2,r2)) l=mid+1;
else r=mid-1;
}
return l-1;
}
int main()
{
//freopen("tmp.in","r",stdin);
//freopen("tmp.out","w",stdout);
BASE[0]=1; for(int i=1;i1]*base;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) cin>>str[i];
for(int i=1;i<=m;i++)
{
scanf("%s",ss);
op[i][0]=ss[0]=='I'?0:1;
scanf("%d%d",&op[i][1],&op[i][2]);
if(!op[i][0]) cin>>add[i];
}
BuildSeg();
for(int i=1;i<=m;i++)
{
int l=op[i][1],r=op[i][2];
if(!op[i][0])
{
Left.lx=l,Left.rx=r,Left.c=op[i][3]; Left.cov(1,1,n);
L.lx=l,L.rx=r,L.c=add[i].size(); L.upd(1,1,n);
if(l+1<=r) height.lx=l+1,height.rx=r,height.c=add[i].size(),height.upd(1,1,n);
if(l-1>0)
{
height.lx=height.rx=l,height.c=cal(l-1)-height.query(1,1,n);
height.upd(1,1,n);
}
if(r1,height.c=cal(r)-height.query(1,1,n);
height.upd(1,1,n);
}
}
else
{
if(l==r) L.lx=L.rx=l,printf("%d\n",L.query(1,1,n));
else height.lx=l+1,height.rx=r,printf("%d\n",height.query(1,1,n));
}
}
return 0;
}