bzoj1014-JSOI2008 火星人prefix
Posted paul120090105(AFO)
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1014-JSOI2008 火星人prefix相关的知识,希望对你有一定的参考价值。
- 题面描述
- 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:(madamimadam),我们将这个字符串的各个字符予以标号:
- 序号
1 2 3 4 5 6 7 8 9 10 11
- 字符
m a d a m i m a d a m
- 序号
- 现在,火星人定义了一个函数(LCQ(x, y)),表示:该字符串中第(x)个字符开始的字串,与该字符串中第(y)个字符开始的字串,两个字串的公共前缀的长度。比方说,(LCQ(1, 7) = 5, LCQ(2, 10) = 1, LCQ(4, 7) = 0) 在研究(LCQ)函数的过程中,火星人发现了这样的一个关联:如果把该字符串的所有后缀排好序,就可以很快地求出(LCQ)函数的值;同样,如果求出了(LCQ)函数的值,也可以很快地将该字符串的后缀排好序。 尽管火星人聪明地找到了求取(LCQ)函数的快速算法,但不甘心认输的地球人又给火星人出了个难题:在求取(LCQ)函数的同时,还可以改变字符串本身。具体地说,可以更改字符串中某一个字符的值,也可以在字符串中的某一个位置插入一个字符。地球人想考验一下,在如此复杂的问题中,火星人是否还能够做到很快地求取(LCQ)函数的值。
- 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀。比方说,有这样一个字符串:(madamimadam),我们将这个字符串的各个字符予以标号:
- 输入格式
- 第一行给出初始的字符串。第二行是一个非负整数(M),表示操作的个数。接下来的(M)行,每行描述一个操作。操作有(3)种,如下所示
- 询问
- 语法:(Q x y),(x,y)均为正整数。
- 功能:计算(LCQ(x,y))限制:(1<=x,y<=当前字符串长度)。
- 修改
- 语法:(R x d),(x)是正整数,(d)是字符。
- 功能:将字符串中第(x)个数修改为字符(d)。限制:(x)不超过当前字符串长度。
- 插入:
- 语法:(I x d),(x)是非负整数,(d)是字符。
- 功能:在字符串第(x)个字符之后插入字符(d),如果(x=0),则在字符串开头插入。
- 限制:(x)不超过当前字符串长度
- 询问
- 第一行给出初始的字符串。第二行是一个非负整数(M),表示操作的个数。接下来的(M)行,每行描述一个操作。操作有(3)种,如下所示
- 输出格式
- 对于输入文件中每一个询问操作,你都应该输出对应的答案。一个答案一行。
- 题解
比较水的题,码量巨大,还卡常(bzoj),我最后是开了手动O3才过的.....- 对于没有 修改 和 插入 操作的题目,一般主流有两种做法
- 建出给定串的 后缀数组 或 后缀自动机,求解
- 用字符串(hash),通过二分公共长度(ans),求解
- 但因为题目中出现 修改 和 插入 操作,而 后缀数组 和 后缀自动机 都是静态的,因此无法维护动态插入、修改
- 因此我们可以用的就只剩下字符串 (hash)了,那么问题相当于转化为动态维护 (hash)序列
- 在中间某一位 (pos)后插入一个数
- 这里我当时写的时候不小心把(ins(pos))写成在(pos)前加一个数,因此之后的 插入操作 被我写成 (ins(pos+1)) 在(pos+1)前加一个数
- 修改其中一个数
- 在中间某一位 (pos)后插入一个数
- 这些操作可以完全被(Splay)胜任
#pragma GCC optimize(3)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
#define ri register
#define il inline
const int inf=1e9;
const int MAXN=1e5+5e4+5;
const int mod=9875321;
int n,m,M,rt;
struct tnode{
int dat,val,fa,sz;
int ch[3];
} t[MAXN];
int p[MAXN];
char s[MAXN];
il int newnode(int val,int fa,int cl,int cr){
t[++M]=(tnode){val,val,fa,1};
t[M].ch[0]=cl; t[M].ch[1]=cr;
return M;
}
il void update(int u){
if (!u) return;
t[0].dat=t[0].sz=0;
int cl=t[u].ch[0],cr=t[u].ch[1];
int szl=t[cl].sz,szr=t[cr].sz;
t[u].sz=szl+szr+1;
t[u].dat=((ll)t[cl].dat*p[szr+1]%mod+(ll)p[szr]*t[u].val%mod+t[cr].dat)%mod;
}
il void rotate(int u){
int f1=t[u].fa;
int f2=t[f1].fa;
int dir1=t[f1].ch[1]==u;
int dir2=t[f2].ch[1]==f1;
int sn=t[u].ch[dir1^1];
t[sn].fa=f1; t[f1].ch[dir1]=sn;
t[f1].fa=u; t[u].ch[dir1^1]=f1;
t[u].fa=f2; t[f2].ch[dir2]=u;
update(f1); update(u);
}
il void splay(int u,int go){
if (u==go) return;
while (t[u].fa!=go){
int f1=t[u].fa;
int f2=t[f1].fa;
int dir1=t[f1].ch[1]==u;
int dir2=t[f2].ch[1]==f1;
if (f2==go){
rotate(u);
break;
}
if (dir1==dir2) rotate(f1);
else rotate(u);
rotate(u);
}
if (go==0) rt=u;
}
int num(int u,int rk){
int cl=t[u].ch[0],cr=t[u].ch[1];
int szl=t[cl].sz,szr=t[cr].sz;
if (cl==0&&cr==0) return u;
if (rk<=szl) return num(cl,rk);
else if (rk>szl+1) return num(cr,rk-szl-1);
else return u;
}
il void ins(int key,char c){
int cdat=c-'a'+1;
if (abs(key)>=inf) cdat=0;
if (rt==0){
rt=newnode(cdat,0,0,0);
return;
}
splay(num(rt,key+1),0);
int u=rt;
int cl=t[u].ch[0];
rt=newnode(cdat,0,cl,u);
t[u].fa=rt; t[cl].fa=rt;
t[u].ch[0]=0;
update(u); update(rt);
}
/*int qry(int key){
splay(num(rt,key+2),0);
// cout<<__func__<<key<<" "<<(char)(t[rt].val+'a'-1)<<" "<<t[t[rt].ch[0]].dat<<endl;
return t[t[rt].ch[0]].dat%mod;
}
bool check(int x,int y,int mid){
int xr=x+mid-1,yr=y+mid-1;
cout<<x<<" "<<xr<<" "<<y<<" "<<yr<<endl;
if (xr>n||yr>n) return 0;
// cout<<qry(xr)<<" "<<qry(x-1)<<endl;
int ansx=(ll)((qry(xr)-(ll)qry(x-1)*p[mid]%mod)%mod+mod)%mod;
int ansy=(ll)((qry(yr)-(ll)qry(y-1)*p[mid]%mod)%mod+mod)%mod;
cout<<ansx<<" "<<ansy<<endl;
return ansx==ansy;
}*/
il int qry(int l,int r){
splay(num(rt,l),0);
splay(num(rt,r+2),rt);
return t[t[t[rt].ch[1]].ch[0]].dat%mod;
}
il bool check(int x,int y,int mid){
int xr=x+mid-1,yr=y+mid-1;
if (xr>n||yr>n) return 0;
return qry(x,xr)==qry(y,yr);
}
il void solve(int x,int y){
if (x==y){
printf("%d
",n-x+1);
return;
}
int l=0,r=max(n-x+1,n-y+1)+1,mid;
// cout<<__func__<<" "<<l<<" "<<r<<endl;
while (l+1<r){
mid=(l+r)>>1;
if (check(x,y,mid)) l=mid;
else r=mid;
}
printf("%d
",l);
}
void prt(int u){
int cl=t[u].ch[0],cr=t[u].ch[1];
printf("id:%d c:%d dat:%d fa:%d cl:%d cr:%d
",u,t[u].val,t[u].dat,t[u].fa,cl,cr);
if (cl) prt(cl);
// printf("%c",(char)t[u].val+'a'-1);
if (cr) prt(cr);
}
int main(){
// freopen("1014.in","r",stdin);
// freopen("1014.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
p[0]=1;
for (ri int i=1;i<=105000;i++) p[i]=(ll)p[i-1]*27%mod;
ins(inf,'a'); ins(-inf,'a');
for (ri int i=1;i<=n;i++) ins(i,s[i]);
// prt(rt);cout<<endl;
scanf("%d",&m);
for (ri int i=1;i<=m;i++){
char c=getchar(); while (c!='Q'&&c!='R'&&c!='I') c=getchar();
int x; scanf("%d",&x);
if (c=='Q'){
int y; scanf("%d",&y);
solve(x,y);
}
if (c=='R'){
char y=getchar(); while (y<'a'||y>'z') y=getchar();
splay(num(rt,x+1),0);
t[rt].val=y-'a'+1;
update(rt);
}
if (c=='I'){
char y=getchar(); while (y<'a'||y>'z') y=getchar();
ins(x+1,y);
n++;
}
// prt(rt); cout<<endl;
}
fclose(stdin); fclose(stdout);
return 0;
}
以上是关于bzoj1014-JSOI2008 火星人prefix的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash