BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分

题目大意:给定一个字符串。提供下列操作:

1.查询从x開始的后缀和从y開始的后缀的最长公共前缀长度

2.将x位置的字符改动为y

3.在x位置的字符后面插入字符y

看到这题一開始我先懵住了。

。这啥。

。我第一时间想到的是后缀数据结构 可是不会写 并且后缀数据结构也不支持改动操作

后来无奈找了题解才知道是Hash+二分。。

。 太强大了 Hash+二分打爆一切啊

用Splay维护这个字符串的改动和插入操作 每一个节点维护子串的Hash值 推断时二分找到最长公共前缀

只是这道题另一些注意事项

1.此题不卡Hash 不会出现ABBABAABBAABABBA之类恶心字符串

2.题目没有明说 可是字符串上全部字符都是小写字母

3.二分时注意上界的取值 不能超过字符串长度 此题不保证x<y 一定要特判 否则就会RE

剩下就非常裸了、、、80%达成 能够补个番了0.0

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
using namespace std;
typedef unsigned long long ll;
struct abcd{
	abcd *fa,*ls,*rs;
	int num,siz;ll hash;
	abcd(int x);
	void Push_Up();
}*null=new abcd(0),*root=null;
abcd :: abcd(int x)
{
	fa=ls=rs=null;
	num=x;siz=x?

1:0;hash=x; } ll ksm[M]; void abcd :: Push_Up() { siz=ls->siz+rs->siz+1; hash=ls->hash*ksm[rs->siz+1]+num*ksm[rs->siz]+rs->hash; } void Zig(abcd *x) { abcd *y=x->fa; y->ls=x->rs; x->rs->fa=y; x->rs=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Zag(abcd *x) { abcd *y=x->fa; y->rs=x->ls; x->ls->fa=y; x->ls=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; y->Push_Up(); if(y==root) root=x; } void Splay(abcd *x,abcd *Tar) { while(1) { abcd *y=x->fa,*z=y->fa; if(y==Tar) break; if(z==Tar) { if(x==y->ls) Zig(x); else Zag(x); break; } if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } x->Push_Up(); } void Find(abcd *x,int y,abcd *z) { while(1) { if(y<=x->ls->siz) x=x->ls; else { y-=x->ls->siz; if(y==1) break; y--; x=x->rs; } } Splay(x,z); } char s[M]; void Build_Tree(abcd *&x,int l,int r) { if(l>r) return ; int mid=l+r>>1; x=new abcd(s[mid]-'a'+1); Build_Tree(x->ls,l,mid-1); Build_Tree(x->rs,mid+1,r); x->ls->fa=x; x->rs->fa=x; x->Push_Up(); } void Initialize() { int i; ksm[0]=1; for(i=1;i<=100010;i++) ksm[i]=ksm[i-1]*31; scanf("%s",s); root=new abcd(19980402); root->rs=new abcd(19980402); Build_Tree(root->rs->ls,0,strlen(s)-1); root->rs->ls->fa=root->rs; root->rs->fa=root; root->rs->Push_Up(); root->Push_Up(); } bool Judge(int x,int y,int ans) { Find(root,x,null); Find(root,x+ans+1,root); ll hash1=root->rs->ls->hash; Find(root,y,null); Find(root,y+ans+1,root); ll hash2=root->rs->ls->hash; return hash1==hash2; } int Query(int x,int y) { int l=0,r=root->siz-2-max(x,y)+1; while(l+1<r) { int mid=l+r>>1; if( Judge(x,y,mid) ) l=mid; else r=mid; } if( Judge(x,y,r) ) return r; return l; } int m; int main() { int i,x,y; char p[10]; Initialize(); cin>>m; for(i=1;i<=m;i++) { scanf("%s",p); if(p[0]=='R') { scanf("%d%s",&x,p); Find(root,x+1,null); root->num=p[0]-'a'+1; root->Push_Up(); } else if(p[0]=='I') { scanf("%d%s",&x,p); Find(root,x+1,null); Find(root,x+2,root); root->rs->ls=new abcd(p[0]-'a'+1); root->rs->ls->fa=root->rs; root->rs->Push_Up(); root->Push_Up(); } else scanf("%d%d",&x,&y),printf("%d\n", Query(x,y) ); } }




posted on 2017-08-18 09:24  wgwyanfs  阅读(120)  评论(0编辑  收藏  举报

导航