BZOJ1014 火星人prefix (splay 哈希 二分答案)
2017-04-09 15:16
302 查看
题目大意
给定一个字符串,要求可以完成以下三种操作:I pos ch 在pos这个位置之后插入字符ch;
R pos ch 将pos这个位置的字符换为ch;
Q x y 查询从x开始的后缀和从y开始的后缀的LCP(最长公共前缀)。
题解
读完题目我首先想到的是后缀数据结构,但是后缀数据结构并不支持修改操作。想了一会儿发现思路并不太对于是我就去翻了大爷的题解,发现是splay+hash+二分答案。大体思路就是用splay结构维护这个字符串,并且在每一个结点维护子树字符串的哈希值。
由于询问操作的答案具有单调性,所以可以用二分答案解决。二分最大公共前缀的长度,检验两部分的哈希值是否相等即可。
一开始听说这题卡哈希,不过貌似并没有啊…
代码
#include <cstdio> #include <iostream> #include <cstring> using namespace std; typedef unsigned long long ull; const int p=8823823; ull powp[int(1e5)+111]; void init_p() { powp[0]=1; for(int i=1;i<int(1e5)+111;i++) powp[i]=powp[i-1]*p; return; } const int maxn=int(2e5)+111; int n,m; char s[maxn]; int a[maxn]; struct Node { int key,siz; ull val; Node *ch[2],*fa; Node(); Node(int); int son() { if(fa->ch[1]==this) return 1; else if(fa->ch[0]==this) return 0; return -1; } int cmp(int pos) { if(pos==ch[0]->siz+1) return -1; return pos<ch[0]->siz+1?0:1; } void maintain() { siz=ch[0]->siz+1+ch[1]->siz; val=ch[0]->val*powp[ch[1]->siz+1] + key*powp[ch[1]->siz] + ch[1]->val; return; } }*null=new Node(),*root=null; Node :: Node():key(0) { siz=null?1:0; val=key; ch[0]=ch[1]=fa=null; } Node :: Node(int _key):key(_key) { siz=null?1:0; val=key; ch[0]=ch[1]=fa=null; } void print(Node* cur) { if(cur==null) return; print(cur->ch[0]); cout<<cur->key<<" "; print(cur->ch[1]); } #define mid ((l+r)>>1) void build(Node* &cur,int l,int r) { if(l>r) {cur=null; return;} cur=new Node(a[mid]); build(cur->ch[0],l,mid-1), cur->ch[0]->fa=cur; build(cur->ch[1],mid+1,r), cur->ch[1]->fa=cur; cur->maintain(); } #undef mid void Rotate(Node* cur,int dir) { Node *tmp=cur->ch[dir^1]; int dir2; cur->ch[dir^1]=tmp->ch[dir]; tmp->ch[dir]->fa=cur; tmp->ch[dir]=cur; cur->maintain(), tmp->maintain(); if(~(dir2=cur->son())) cur->fa->ch[dir2]=tmp; tmp->fa=cur->fa, cur->fa=tmp; //cur=tmp return; } void Splay(Node* cur) { int dir; while(~(dir=cur->son())) { if(dir==cur->fa->son()) Rotate(cur->fa->fa,dir^1); Rotate(cur->fa,dir^1); } } Node* _find(Node* cur,int k) { int dir=cur->cmp(k); if(dir==1) k-=cur->ch[0]->siz+1; if(dir==-1) return cur; else return _find(cur->ch[dir],k); } Node* Merge(Node* lhs,Node* rhs) { if(lhs==null) return rhs; if(rhs==null) return lhs; Node *tmp=_find(lhs,lhs->siz); Splay(tmp); tmp->ch[1]=rhs, rhs->fa=tmp, tmp->maintain(); return tmp; } void Split(Node* org,int dir,Node*& l,Node*& r) { Splay(org); if(!dir) l=org->ch[0], r=org; else l=org, r=org->ch[1]; org->ch[dir]->fa=null, org->ch[dir]=null, org->maintain(); return ; } void Modify(Node* &cur,int pos,int val) { Node *tmp=_find(cur,pos); Splay(tmp); tmp->key=val, tmp->maintain(); cur=tmp; } void Insert(Node* &cur,int pos,int val) { Node *add=new Node(val); if(pos==0) { cur=Merge(add,cur); return; } Node *lhs,*rhs; Split(_find(cur,pos),1,lhs,rhs); lhs=Merge(Merge(lhs,add),rhs); cur=lhs; } unsigned long long Get_hash(Node* cur,int l,int len) { Node *lhs,*mid,*rhs,*tmp; ull res; Split(_find(root,l),0,lhs,mid); Split(_find(mid,len),1,mid,rhs); res=mid->val; root=Merge(Merge(lhs,mid),rhs); return res; } int solve(int x,int y) { int l=1, r=root->siz-max(x,y)+1, res=0; while(l<=r) { int mid=(l+r)>>1; if(Get_hash(root,x,mid)==Get_hash(root,y,mid)) l=mid+1, res=mid; else r=mid-1; } return res; } int main() { #ifndef ONLINE_JUDGE freopen("input.txt","r",stdin); freopen("output.txt","w",stdout); #endif // ONLINE_JUDGE init_p(); scanf("%s%d",s+1,&m); n=strlen(s+1); for(int i=1;i<=n;i++) a[i]=s[i]-'a'+1; build(root,1,n); for(int i=0;i<m;i++) { char op[5]; scanf("%s",op); if(op[0]=='Q') { int x,y; scanf("%d%d",&x,&y); printf("%d\n",solve(x,y)); } else if(op[0]=='I') { int pos; char ch; scanf("%d %c",&pos,&ch); Insert(root,pos,ch-'a'+1); } else { int pos; char ch; scanf("%d %c",&pos,&ch); Modify(root,pos,ch-'a'+1); } } return 0; }
相关文章推荐
- BZOJ 1014 火星人 prefix (splay hash 二分答案)
- BZOJ1014 火星人prefix Splay维护序列hash值+二分答案判LCP
- [bzoj1014][JSOI2008]火星人prefix【splay】【哈希】【二分】
- BZOJ 1014 [JSOI2008]火星人prefix (Splay + Hash + 二分)
- [BZOJ]1014: [JSOI2008]火星人prefix splay+hash+二分
- 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解
- bzoj 1014: [JSOI2008]火星人prefix(splay维护区间+Hash+二分)
- [bzoj1014](JSOI2008)火星人 prefix (Splay维护哈希)
- BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分
- BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】
- 【BZOJ1014】【JSOI2008】火星人prefix Splay处理区间,hash+dichotomy(二分)check出解
- 【bzoj1014】[JSOI2008]火星人prefix splay+hash+二分
- bzoj1014 [JSOI2008]火星人prefix(二分答案+哈希+平衡树)
- BZOJ 1014 JSOI 2008 火星人prefix Splay维护字符串Hash + 二分
- BZOJ_1014_[JSOI2008]_火星人prefix_(Splay+LCP_Hash+二分)
- bzoj1014: [JSOI2008]火星人prefix(splay+hash+二分)
- 【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)
- [BZOJ1014][JSOI2008]火星人prefix splay+二分+hash
- BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分
- [bzoj1014][splay][JSOI2008]火星人prefix