Description
给你一个字符串S,初始长度为len,还有一个n个元素的序列P。
接下来m个操作,有三种类型,分别是:
- 在字符串前面加入一个字符
- 修改P中一个元素的值
- 询问对于所有i∈[l,r],使得S[L-P[i]+1…L]字典序最小的i(有多个则输出最小的i,L是当前字符串长度)
(强制在线)
Input
输入共 m + 3 行。
第一行为三个整数n, m, len。
第二行为初始字符串S。
第三行,n个数,表示P[1]…p[n]。
接下来 m 行,每行表示一个操作。
-
I c 在字符串最前的位置加入第 (c xor lastans)+1 个小写字母,其中lastans 为上一
次Q询问的答案,初始为0。
-
C x pos 将P[x]修改为pos。
-
Q l r 表示询问[l…r]区间。
Output
对于每个Q询问输出一行,表示答案。
Sample Input
3 3 5
horni
3 2 5
I 15
C 1 6
Q 1 3
Sample Output
3
Hint
对于10%的数据,1<=n<=100,1<=m<=100,1<=len<=100,1<=P[i]<=len。
对于100%的数据, 1<=n<=500000,1<=m<=800000,1<=len<=100000,1<=P[i]<=len。
I操作中0<=c xor lastans<=25。
C操作中1<=x<=n,1<=pos<=当前字符串长度。
Q操作中1<=l,r<=n。
I操作数量约占总操作数量的1/5,C,Q操作数量约各占总操作数量的2/5。
思路
后缀平衡树。I操作就是在平衡树中新加入一个后缀,然后用线段树维护P数组区间最小的后缀,修改和询问都是简单的线段树操作。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
typedef pair<int,int> pii;
typedef pair<ll,int> pli;
const ll inf=0x7fffffffffffffff;
int p[2000077];
char s[2000077];
ll rk[2000077];
int cmp(int x,int y)
{
if(s[x]!=s[y])
return s[x]<s[y];
return rk[x-1]<rk[y-1];
}
struct suf
{
int x;
suf(int a=0)
{
x=a;
}
};
int operator <(suf a,suf b)
{
return cmp(a.x,b.x);
}
typedef pair<suf,int> psi;
namespace sgt
{
int ls[1000010];
int rs[1000010];
psi s[1000010];
int cnt=0;
int rt;
void build(int &p,int l,int r)
{
p=++cnt;
if(l==r)
return;
int mid=(l+r)>>1;
build(ls[p],l,mid);
build(rs[p],mid+1,r);
}
void change(int p,int x,psi v,int L,int R)
{
if(L==R)
{
s[p]=v;
return;
}
int mid=(L+R)>>1;
if(x<=mid)
change(ls[p],x,v,L,mid);
else
change(rs[p],x,v,mid+1,R);
s[p]=min(s[ls[p]],s[rs[p]]);
}
psi query(int p,int l,int r,int L,int R)
{
if(l<=L&&r>=R)
return s[p];
int mid=(L+R)>>1;
if(r<=mid)
return query(ls[p],l,r,L,mid);
if(l>mid)
return query(rs[p],l,r,mid+1,R);
return min(query(ls[p],l,r,L,mid),query(rs[p],l,r,mid+1,R));
}
};
namespace sct
{
struct node
{
int v;
int s;
int ls,rs;
ll k;
ll l,r;
};
node a[2000010];
int cnt=0;
int rt=0;
int *b;
void insert(int &p,int v,ll l,ll r)
{
if(!p)
{
p=++cnt;
a[p].s=1;
a[p].v=v;
a[p].l=l;
a[p].r=r;
a[p].k=l+((r-l)>>1);
a[p].ls=a[p].rs=0;
rk[v]=a[p].k;
return;
}
a[p].s++;
if(cmp(v,a[p].v))
{
insert(a[p].ls,v,l,a[p].k-1);
if(a[a[p].ls].s>a[p].s*0.7)
b=&p;
}
else
{
insert(a[p].rs,v,a[p].k+1,r);
if(a[a[p].rs].s>a[p].s*0.7)
b=&p;
}
}
int t;
int c[1000010];
int d[1000010];
void dfs(int &p)
{
if(a[p].ls)
dfs(a[p].ls);
c[++t]=p;
d[t]=a[p].v;
if(a[p].rs)
dfs(a[p].rs);
p=0;
}
void build(int &p,int l,int r,ll L,ll R)
{
int mid=(l+r)>>1;
ll k=L+((R-L)>>1);
p=c[mid];
a[p].v=d[mid];
rk[a[p].v]=k;
a[p].l=L;
a[p].r=R;
a[p].s=r-l+1;
a[p].k=k;
a[p].ls=a[p].rs=0;
if(l<mid)
build(a[p].ls,l,mid-1,L,k-1);
if(r>mid)
build(a[p].rs,mid+1,r,k+1,R);
}
void build()
{
ll l=a[*b].l;
ll r=a[*b].r;
t=0;
dfs(*b);
build(*b,1,t,l,r);
}
}
int main()
{
int n,m,len;
scanf("%d%d%d",&n,&m,&len);
scanf("%s",s+1);
reverse(s+1,s+len+1);
rk[0]=-1;
int i;
for(i=1;i<=len;i++)
{
sct::b=0;
sct::insert(sct::rt,i,0,inf);
if(sct::b)
sct::build();
}
char op[5];
int last=0;
int x,y;
sgt::build(sgt::rt,1,n);
for(i=1;i<=n;i++)
{
scanf("%d",&x);
sgt::change(sgt::rt,i,psi(suf(x),i),1,n);
}
for(i=1;i<=m;i++)
{
scanf("%s",op);
if(op[0]=='I')
{
scanf("%d",&x);
x^=last;
s[++len]=x+'a';
sct::b=0;
sct::insert(sct::rt,len,0,inf);
if(sct::b)
sct::build();
}
else if(op[0]=='C')
{
scanf("%d%d",&x,&y);
sgt::change(sgt::rt,x,psi(suf(y),x),1,n);
}
else
{
scanf("%d%d",&x,&y);
psi ans=sgt::query(sgt::rt,x,y,1,n);
last=ans.second;
printf("%d\n",last);
}
}
return 0;
}