タイトル
あなたは、文字列を持っていますか。
あなたは両方をサポートする必要があります。
1:Cの末尾に文字列を挿入
2:現在の文字列[L、R]異なるサブサブストリングの列の数を照会します
オンラインの強制
N、M <= 50000
思考
暴力:
SAMは、O(Nを直接使用することである。3の)
正解:
この問題の動作はそのSAM 1で拡張することがわかります。
二次エンドをlenのビットのすべてのサブストリングに拡張するとき、文字列の長さlen一度設定操作後に、文字列が増大します。
両親SAMの部分文字列にこれらの対応は、チェーンのルートにツリーのリーフノードであり、リーフノードは、文字列の新しい子ノードS1⋯LENことを示しています。
私たちは、両親SAMツリーのLCTの動的なメンテナンスの使用を検討するようにします。
(ああ嫌な、唯一の神々は、シーンが来ることができます)
スプレイで同じで最後の場所
我々は、区間[L、R]異なるサブストリングの数を維持する方法を検討します。
この問題は、そこに区間[L、R]どのように多くの異なる番号を必ず、あなたの数nを与える尋ねるように簡略化することができます。
このように、包含と除外!!!非数の合計数を引いたものが最後に出現。
iビットプラス1程度である木のi番目の会長のi番目のバージョンを追加し、フロントから各番号に追加順番に背中に、前処理の答えを考えてみましょう。数本は前に、位置はLSTの発生に設けられている場合、i番目のバージョンのツリー椅子マイナス1のj番目のビット。
間隔に異なるサブストリングの数は、同様に、ツリーの議長によって解決することができます。
だから、コードコードコード!!!!!
ロング、200行
コード
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+77;
int n,m,maxlen,rt[N][2];
struct SegmentTree
{
int ls[N*100],rs[N*100],sz,siz[N*100];
ll sumv[N*100];
int cpyNode(int pre)
{
int x=++sz;
ls[x]=ls[pre];
rs[x]=rs[pre];
sumv[x]=sumv[pre];
siz[x]=siz[pre];
return x;
}
void update(int & o,int pre,int l,int r,int ql,int qr,int v)
{
o=cpyNode(pre);
if(ql==l && qr==r) { sumv[o]+=v,siz[o]++; return; }
int mid=(l+r)>>1;
if(qr<=mid)
update(ls[o],ls[pre],l,mid,ql,qr,v);
else if(ql>mid)
update(rs[o],rs[pre],mid+1,r,ql,qr,v);
else
update(ls[o],ls[pre],l,mid,ql,mid,v),
update(rs[o],rs[pre],mid+1,r,mid+1,qr,v);
}
int querySize(int o,int l,int r,int p)
{
if(l==r) return siz[o];
int mid=(l+r)>>1;
int Ans=siz[o];
if(p<=mid) Ans+=querySize(ls[o],l,mid,p);
else Ans+=querySize(rs[o],mid+1,r,p);
return Ans;
}
ll querySum(int o,int l,int r,int p)
{
if(l==r) return sumv[o];
int mid=(l+r)>>1;
ll Ans=sumv[o];
if(p<=mid) Ans+=querySum(ls[o],l,mid,p);
else Ans+=querySum(rs[o],mid+1,r,p);
return Ans;
}
}rap;
namespace LCT
{
static const int SIZE=2e5+77;
int ch[SIZE][2],fa[SIZE];
int pos[SIZE],len[SIZE];
bool isrt(int x) { return !fa[x] || (ch[fa[x]][0] != x && ch[fa[x]][1] != x); }
bool c(int x) { return ch[fa[x]][1]==x; }
void rotate(int x)
{
int f=fa[x],p=fa[f],d=c(x);
if(!isrt(f)) ch[p][c(f)]=x;
fa[x]=p;
ch[f][d]=ch[x][d^1]; fa[ch[f][d]]=f;
ch[x][d^1]=f; fa[f]=x;
}
int findrt(int x) { return !isrt(x) ? findrt(fa[x]) : x; }
void splay(int x)
{
swap(pos[findrt(x)],pos[x]);
while(!isrt(x))
{
int f=fa[x];
if(!isrt(f))
{
if(c(f)==c(x)) rotate(f);
else rotate(x);
}
rotate(x);
}
}
void access(int x,int i)
{
rt[i][0]=rt[i-1][0];
rt[i][1]=rt[i-1][1];
for(int v=0; x; v=x,x=fa[x])
{
splay(x);
if(len[x] && pos[x])
{
int pl=pos[x]-len[x]+1,pr=pos[x]-len[fa[x]];
if(pl>1) rap.update(rt[i][0],rt[i][0],1,maxlen,1,pl-1,pr-pl+1);
rap.update(rt[i][1],rt[i][1],1,maxlen,pl,pr,pr);
}
if(ch[x][1]) pos[ch[x][1]]=pos[x];
ch[x][1]=v;
pos[v]=0;
pos[x]=i;
}
}
void cut(int x)
{
splay(x);
pos[ch[x][0]]=pos[x];
fa[ch[x][0]]=fa[x];
ch[x][0]=0;
}
void link(int x,int y)
{
splay(x);
fa[x]=y;
}
}
struct SAM
{
static const int SIZE=2e5+77;
int nxt[SIZE][26],fa[SIZE],sz,pos[SIZE],len[SIZE],rt,last;
SAM() { init(); }
int newnode(int l,int id)
{
memset(nxt[sz],0,sizeof(nxt[sz]));
pos[sz]=id;
fa[sz]=0;
len[sz]=l;
return sz++;
}
void init()
{
sz=1;
rt=newnode(0,0);
last=rt;
}
void add(char x,int i)
{
int c=x-'a';
int now=newnode(len[last]+1,i);
LCT::len[now]=len[now];
int p=last;
while(p && !nxt[p][c])
{
nxt[p][c]=now;
p=fa[p];
}
if(!p) LCT::link(now,fa[now]=rt);
else
{
int q=nxt[p][c];
if(len[p]+1==len[q])
LCT::link(now,fa[now]=q);
else
{
int u=newnode(len[p]+1,pos[q]);
LCT::len[u]=len[u];
for(int i=0; i<26; i++) nxt[u][i]=nxt[q][i];
LCT::cut(q);
LCT::pos[u]=LCT::pos[q];
LCT::link(u,fa[u]=fa[q]);
LCT::link(now,fa[now]=u);
LCT::link(q,fa[q]=u);
while(nxt[p][c]==q)
{
nxt[p][c]=u;
p=fa[p];
}
}
}
LCT::access(now,i);
last=now;
}
}cxk;
char str[N];
int type;
int main()
{
scanf("%d",&type);
scanf("%s %d",str+1,&m);
n=strlen(str+1);
maxlen=n+m;
for(int i=1; i<=n; i++)
cxk.add(str[i],i);
ll lastans=0;
for(int i=1; i<=m; i++)
{
int opt;
scanf("%d",&opt);
if(opt==1)
{
char ch[5];
scanf("%s",ch);
str[++n]=(ch[0]-'a'+type*lastans)%26+'a';
cxk.add(str[n],n);
}
else
{
int l,r;
scanf("%d%d",&l,&r);
l=(l-1+lastans*type)%n+1;
r=(r-1+lastans*type)%n+1;
ll val1=rap.querySum(rt[r][0],1,maxlen,l);
ll val2=rap.querySum(rt[r][1],1,maxlen,l);
ll val3=rap.querySize(rt[r][1],1,maxlen,l);
lastans=1ll*(r-l+1)*(r-l+2)/2ll;
lastans-=val1;
lastans-=val2-1ll*(l-1)*val3;
printf("%lld\n",lastans);
}
}
}