bzoj1014 JSOI2008—火星人prefix
Posted MashiroSky
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1014 JSOI2008—火星人prefix相关的知识,希望对你有一定的参考价值。
http://www.lydsy.com/JudgeOnline/problem.php?id=1014 (题目链接)
题意
给出一个字符串,要求维护这些操作:询问后缀x与后缀y的LCQ(最长公共前缀),在第k个字符后插入一个字符,将第k个字符改成另一个字符。
Solution
对于修改与插入操作,我们用splay维护。考虑怎么求解LCQ。
我们可以将字符串hash,然后平衡树上每一个节点的hash值就代表的该区间的hash值,毫无疑问,这是可以向上更新的。于是问题就解决了。
代码
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #define LL long long #define inf 2147483640 #define MOD 9875321 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; const int maxn=150010; int tr[maxn][2],fa[maxn],id[maxn],size[maxn]; int v[maxn],h[maxn],bin[maxn]; int n,rt,sz,q; char s[maxn]; void update(int k) { int l=tr[k][0],r=tr[k][1]; size[k]=size[l]+size[r]+1; h[k]=h[l]+(LL)v[k]*bin[size[l]]%MOD+(LL)bin[size[l]+1]*h[r]%MOD; h[k]%=MOD; } void rotate(int x,int &k) { int y=fa[x],z=fa[y],l,r; l=tr[y][1]==x;r=l^1; if (y==k) k=x; else tr[z][tr[z][1]==y]=x; fa[x]=z;fa[y]=x;fa[tr[x][r]]=y; tr[y][l]=tr[x][r];tr[x][r]=y; update(y);update(x); } void splay(int x,int &k) { while (x!=k) { int y=fa[x],z=fa[y]; if (y!=k) { if ((tr[z][0]==y) ^ (tr[y][0]==x)) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int k,int x) { int l=tr[k][0],r=tr[k][1]; if (size[l]+1==x) return k; else if (size[l]>=x) return find(l,x); else return find(r,x-size[l]-1); } void insert(int k,int val) { int x=find(rt,k+1),y=find(rt,k+2); splay(x,rt);splay(y,tr[x][1]); int z=++sz;tr[y][0]=z;fa[z]=y;v[z]=val; update(z);update(y);update(x); } int query(int k,int val) { int x=find(rt,k),y=find(rt,k+val+1); splay(x,rt);splay(y,tr[x][1]); return h[tr[y][0]]; } int solve(int x,int y) { int l=1,r=min(sz-x,sz-y)-1,ans=0; while (l<=r) { int mid=(l+r)>>1; if (query(x,mid)==query(y,mid)) l=mid+1,ans=mid; else r=mid-1; } return ans; } void build(int l,int r,int f) { if (l>r) return; int mid=(l+r)>>1,now=id[mid],last=id[f]; if (l==r) { v[now]=h[now]=s[mid]-‘a‘+1; fa[now]=last;size[now]=1; tr[last][mid>=f]=now; return; } build(l,mid-1,mid);build(mid+1,r,mid); v[now]=s[mid]-‘a‘+1;fa[now]=last;update(now); tr[last][mid>=f]=now; } int main() { scanf("%s",s+2); n=strlen(s+2); bin[0]=1;for (int i=1;i<maxn;i++) bin[i]=bin[i-1]*31%MOD; for (int i=1;i<=n+2;i++) id[i]=i; build(1,n+2,0);rt=(n+3)>>1;sz=n+2; scanf("%d",&q); while (q--) { int x,y;char ch[10]; scanf("%s",ch); scanf("%d",&x); if (ch[0]==‘Q‘) scanf("%d",&y),printf("%d\n",solve(x,y)); if (ch[0]==‘R‘) { scanf("%s",ch); x=find(rt,x+1);splay(x,rt); v[rt]=ch[0]-‘a‘+1;update(rt); } if (ch[0]==‘I‘) scanf("%s",ch),insert(x,ch[0]-‘a‘+1); } return 0; }
以上是关于bzoj1014 JSOI2008—火星人prefix的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)