bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)
Posted Sakits
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)相关的知识,希望对你有一定的参考价值。
题目大意:一个字符串三个操作:①求两个后缀的LCP②插入一个字符③修改一个字符。
前几天刚学了hash+二分求lcp,就看到这题。
原来splay还能这么用?!原来splay模板这么好写?我以前写的splay是假的吧woc
splay每个节点代表一个字符,并维护这个子树代表一个子串的哈希值。因为splay旋转不破坏树结构,所以不论怎么旋转这棵splay树都能代表这个字符串。
预处理处理少了调了半天呜呜呜
赶紧跑去更新自己的splay模板
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define which(x) (son[fa[x]][1]==x) #define ull unsigned long long using namespace std; const int maxn=500010; int n,m,x,y,tot,root; int fa[maxn],son[maxn][2],size[maxn],s[maxn]; ull hs[maxn],mul[maxn]; char st[maxn],ch[maxn],ch2[maxn]; void read(int &k) { int f=1;k=0;char c=getchar(); while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar(); while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar(); k*=f; } void update(int x) { size[x]=size[son[x][0]]+size[son[x][1]]+1; hs[x]=hs[son[x][0]]+mul[size[son[x][0]]]*s[x]+mul[size[son[x][0]]+1]*hs[son[x][1]]; } void rotate(int x) { int f=fa[x]; bool k=which(x); son[f][k]=son[x][!k]; son[x][!k]=f; son[fa[f]][which(f)]=x; fa[son[f][k]]=f; fa[x]=fa[f]; fa[f]=x; size[x]=size[f]; hs[x]=hs[f]; update(f); } void splay(int x,int g) { while(fa[x]!=g) { int f=fa[x]; if(fa[f]==g) { rotate(x); break; } if(which(x)^which(f))rotate(x); else rotate(f); rotate(x); } if(!g)root=x; } int rank(int x,int k) { if(k<=size[son[x][0]])return rank(son[x][0],k); else if(k==(size[son[x][0]]+1))return x; else return rank(son[x][1],k-size[son[x][0]]-1); } int build(int l,int r,int f) { if(l>r)return 0; int x=++tot,mid=(l+r)>>1; fa[x]=f;s[x]=(int)(st[mid]-‘a‘)+1; son[x][0]=build(l,mid-1,x); son[x][1]=build(mid+1,r,x); update(x); return x; } void insert(int k,int ch) { int x=rank(root,k),y=rank(root,k+1); splay(x,0);splay(y,x); s[++tot]=ch; fa[tot]=y;son[y][0]=tot; update(tot);update(y);update(x); } void change(int k,int ch) { int x=rank(root,k); splay(x,0); s[x]=ch; update(x); } int lcp(int kx,int ky) { int l=0,r=n; while(l<r) { int mid=(l+r+1)>>1; if(ky+mid>n+2) { r=mid-1; continue; } int x=rank(root,kx-1),y=rank(root,kx+mid); splay(x,0);splay(y,x); ull haxi=hs[son[y][0]]; x=rank(root,ky-1),y=rank(root,ky+mid); splay(x,0);splay(y,x); if(haxi==hs[son[y][0]])l=mid; else r=mid-1; } return l; } int main() { scanf("%s",st+1); n=strlen(st+1); mul[0]=1; for(int i=1;i<=150010;i++)mul[i]=mul[i-1]*27; root=build(0,n+1,0); read(m); for(int i=1;i<=m;i++) { scanf("%s",ch); if(ch[0]==‘Q‘) { read(x);read(y); if(x>y)swap(x,y); if(x!=y)printf("%d\n",lcp(x+1,y+1)); else printf("%d\n",n-x+1); } if(ch[0]==‘R‘) { read(x); scanf("%s",ch2); change(x+1,(int)(ch2[0]-‘a‘)+1); } if(ch[0]==‘I‘) { read(x); scanf("%s",ch2); insert(x+1,(int)(ch2[0]-‘a‘)+1); n++; } } return 0; }
以上是关于bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
[BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
[BZOJ]1014 火星人prefix(JSOI2008)