Description
给定一个字符串和n个pos,要求资瓷:
- 开头插入一个字符c
- 将第x个pos改为y
- 查询第l到r个pos中所代表的最大后缀
强制在线
Solution
久违的串串题。感觉后缀平衡树好像挺好写的,在线还能logn。
由于强制在线我们不能用SA,因为只存在前端插入因此考虑新增后缀的排名怎么维护。
比较两个后缀等价于分别比较首字母和下一位后缀的rank,由于这四个东西都是已知的因此比较就是O(1)的了。
我们可以把rank映射来维护后缀排名的相对大小,也正是因为这样我们才需要用一种重量平衡的平衡树来维护SA序列。这里写treap旋转的时候暴力修改,或者替罪羊暴力重构都是可以的,感觉替罪羊树要科学一些( ╯□╰ )
快速求出了rank之后就是简单的线段树上问题了
一开始挂了很多次是因为随机数值域没开够,太菜了orz
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const LL INF=(1LL<<61);
const int N=1000005;
struct treeNode {
int son[2],fa,pri;
LL L,R,rnk;
} t[N];
int mn[N<<2],pos[N],root;
char str[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void build(int x) {
LL mid=(t[x].L+t[x].R)/2;
t[x].rnk=mid;
if (t[x].son[0]) {
t[t[x].son[0]].L=t[x].L;
t[t[x].son[0]].R=mid-1;
build(t[x].son[0]);
}
if (t[x].son[1]) {
t[t[x].son[1]].L=mid+1;
t[t[x].son[1]].R=t[x].R;
build(t[x].son[1]);
}
}
void rotate(int x) {
int y=t[x].fa; int z=t[y].fa;
int k=t[y].son[1]==x;
t[y].son[k]=t[x].son[!k]; t[t[x].son[!k]].fa=y;
t[y].fa=x; t[x].son[!k]=y;
t[x].fa=z; t[z].son[t[z].son[1]==y]=x;
t[x].L=t[y].L; t[x].R=t[y].R;
build(x);
}
bool les(int x,int y) {
return (str[x]==str[y])?(t[x-1].rnk<=t[y-1].rnk):(str[x]<str[y]);
}
void ins(int x,int nw) {
int k=les(x,nw);
if (!t[x].son[k]) {
t[x].son[k]=nw;
t[nw].pri=rand()*rand();
t[nw].fa=x;
LL mid=(t[x].L+t[x].R)/2;
if (!k) t[nw].L=t[x].L,t[nw].R=mid-1;
else t[nw].L=mid+1,t[nw].R=t[x].R;
t[nw].rnk=(t[nw].L+t[nw].R)>>1;
} else ins(t[x].son[k],nw);
if (t[t[x].son[k]].pri>t[x].pri) {
if (x==root) root=t[x].son[k];
rotate(t[x].son[k]);
}
}
void modify(int now,int tl,int tr,int x) {
if (tl==tr) return (void) (mn[now]=x);
int mid=(tl+tr)>>1;
if (x<=mid) modify(now<<1,tl,mid,x);
else modify(now<<1|1,mid+1,tr,x);
if (les(pos[mn[now<<1]],pos[mn[now<<1|1]])) mn[now]=mn[now<<1];
else mn[now]=mn[now<<1|1];
}
int query(int now,int tl,int tr,int l,int r) {
if (r<l) return 0;
if (tl>=l&&tr<=r) return mn[now];
int mid=(tl+tr)>>1;
int qx=query(now<<1,tl,mid,l,std:: min(r,mid));
int qy=query(now<<1|1,mid+1,tr,std:: max(mid+1,l),r);
if (qx*qy==0) return qx+qy;
return (les(pos[qx],pos[qy]))?(qx):(qy);
}
int main(void) {
srand(20020303);
freopen("data.in","r",stdin);
freopen("myp.out","w",stdout);
int n=read(),m=read(),len=read(),type=read();
scanf("%s",str+1); str[0]=-1;
rep(i,1,len/2) std:: swap(str[i],str[len-i+1]);
root=1; t[1].L=0,t[1].R=INF; t[1].rnk=INF/2; t[1].pri=rand()*rand();
rep(i,2,len) ins(root,i);
rep(i,1,n) {
pos[i]=read();
modify(1,1,n,i);
}
for (int lastans=0,ch;m--;) {
for (ch=getchar();ch!='Q'&&ch!='I'&&ch!='C';ch=getchar());
if (ch=='I') {
int x=read()^(type*lastans);
str[++len]=x+'a';
ins(root,len);
} else if (ch=='C') {
int x=read(); pos[x]=read();
modify(1,1,n,x);
} else {
int l=read(),r=read();
printf("%d\n", lastans=query(1,1,n,l,r));
}
}
return 0;
}