bzoj1014 [JSOI2008]火星人prefix ( splay + hash )
来源:互联网 发布:美容院微管理软件 编辑:程序博客网 时间:2024/05/16 12:05
bzoj1014 [JSOI2008]火星人prefix
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1014
题意:
给定一个字符串,比方说,有这样一个字符串:madamimadam,
我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 8 9 10 11 字符 m a d a m i m a d a m
有3种操作:
1、询问。语法:Q x y,x, y均为正整数。
功能:计算LCQ(x, y)
2、修改。语法:R x d,x是正整数,d是字符。
功能:将字符串中第x个数修改为字符d。
限制:x不超过当前字符串长度。
3、插入:语法:I x d,x是非负整数,d是字符。
功能:在字符串第x个字符之后插入字符d,如果x = 0,则在字符串开头插入。
限制:x不超过当前字符串长度。
第一行给出初始的字符串。第二行是一个非负整数M,表示操作的个数。
数据范围
1、所有字符串自始至终都只有小写字母构成。
2、M<=150,000
3、字符串长度L自始至终都满足L<=100,000
4、询问操作的个数不超过10,000个。
题解:
复习一发spaly。
首先我们知道二分比较hash值可以log地得到两个串的最长公共前缀,而给出的替换和插入操作可以让我们想到splay维护。
于是我们用splay维护字符串,每个节点上存有它控制的区间的hash值。每次查询两个后缀的最长公共前缀,只需要二分长度,然后把这个区间转上去,重算hash值,比较这两个区间的hash值是否相同即可。
( wa点:size没搞对,二分的时候越界了。改回来时影响了关于查询的两个串是同一个串的情况,其实不用特判。)
代码:
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<cmath>#define LL unsigned long longusing namespace std;const int N=100010;const int M=150010;const LL base=131;int root,tail=0,fa[N];struct node{ int ch[2],size; LL val,key;}tr[N];int m,len;LL mi[N];char s[M],opt[5];void update(int x){ int ls=tr[x].ch[0]; int rs=tr[x].ch[1]; tr[x].key=tr[x].val; tr[x].size=1; if(rs) { tr[x].size+=tr[rs].size; tr[x].key=tr[x].key*mi[tr[rs].size]+tr[rs].key; } if(ls) { tr[x].size+=tr[ls].size; tr[x].key=tr[ls].key*mi[tr[x].size-tr[ls].size]+tr[x].key; } return;}void build(int &nd,int lf,int rg,int f){ if(lf>rg) return; nd=++tail; fa[nd]=f; tr[nd].ch[0]=tr[nd].ch[1]=0; if(lf==rg) { tr[nd].size=1; tr[nd].val=tr[nd].key=(int)s[lf]; return; } int mid=(lf+rg)>>1; tr[nd].val=s[mid]; build(tr[nd].ch[0],lf,mid-1,nd); build(tr[nd].ch[1],mid+1,rg,nd); update(nd);}int find(int nd,int pos){ int ls=tr[nd].ch[0]; int rs=tr[nd].ch[1]; if(pos==tr[ls].size+1) return nd; else if(pos<=tr[ls].size) return find(tr[nd].ch[0],pos); else return find(tr[nd].ch[1],pos-tr[ls].size-1);}void rotate(int x,int &k){ int y=fa[x]; int z=fa[y]; int l,r; if(x==tr[y].ch[0]) l=0; else l=1; r=l^1; if(y==k) k=x; else if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x; fa[x]=z; tr[y].ch[l]=tr[x].ch[r]; fa[tr[x].ch[r]]=y; tr[x].ch[r]=y; fa[y]=x; update(y); update(x);}void splay(int x,int &k){ while(x!=k) { int y=fa[x]; int z=fa[y]; if(y!=k) { if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x,k); else rotate(y,k); } rotate(x,k); }}LL check(int l,int r){ splay(l,root); splay(r,tr[l].ch[1]); int nd=tr[tr[l].ch[1]].ch[0]; return tr[nd].key;}int query(int p,int q) //询问x,y的lcp { int x=find(root,p); int y=find(root,q); if(tr[x].val!=tr[y].val) return 0; int lx,rx,ly,ry; lx=find(root,p-1); ly=find(root,q-1); int sz=tr[root].size; int lf=1; int rg=min(sz-p,sz-q); while(lf+1<rg) { int mid=(lf+rg)>>1; rx=find(root,p+mid); LL v1=check(lx,rx); ry=find(root,q+mid); LL v2=check(ly,ry); if(v1==v2) lf=mid; else rg=mid; } int ans; rx=find(root,p+rg); LL v1=check(lx,rx); ry=find(root,q+rg); LL v2=check(ly,ry); if(v1==v2) ans=rg; else ans=lf; return ans;}int main(){ mi[0]=1; for(int i=1;i<N;i++) mi[i]=mi[i-1]*base; scanf("%s",s+2); len=strlen(s+2); tr[0].size=0; build(root,1,len+2,0); scanf("%d",&m); while(m--) { scanf("%s",opt); if(opt[0]=='Q') { int x,y; scanf("%d%d",&x,&y); x++; y++; printf("%d\n",query(x,y)); } else if(opt[0]=='R') { int pos; char ccc[5]; scanf("%d",&pos); scanf("%s",ccc); pos++; int c=(int)ccc[0]; int nd=find(root,pos); splay(nd,root); tr[nd].val=c; update(nd); } else { int pos; char ccc[5]; scanf("%d",&pos); scanf("%s",ccc); pos++; int c=(int)ccc[0]; int f=find(root,pos); splay(f,root); int nd=++tail; tr[nd].val=c; tr[nd].ch[1]=tr[f].ch[1]; fa[tr[nd].ch[1]]=nd; tr[f].ch[1]=nd;fa[nd]=f; tr[nd].ch[0]=0; update(nd); update(f); } } return 0;}
专心,专心。
不理我算啦 (′へ` )
- 【bzoj1014】[JSOI2008]火星人prefix splay+hash+二分
- 【bzoj1014】【jsoi2008】【火星人prefix】【splay+hash】
- 【BZOJ1014】[JSOI2008]火星人prefix【Splay】【Hash】
- bzoj1014 [JSOI2008]火星人prefix ( splay + hash )
- bzoj1014: [JSOI2008]火星人prefix splay
- [bzoj1014][splay][JSOI2008]火星人prefix
- [BZOJ1014]JSOI2008 火星人|splay|hash
- [BZOJ1014] [JSOI2008]火星人prefix && splay+字符串hash 重写版
- BZOJ1014 [JSOI2008]火星人prefix(Splay+字符串Hash)
- [BZOJ1014] [JSOI2008] 火星人prefix - splay + hash + 二分答案
- [BZOJ1014][JSOI2008][Splay][RKHash]火星人prefix
- [splay+二分+哈希] BZOJ1014: [JSOI2008]火星人prefix
- bzoj1014: [JSOI2008]火星人prefix(Splay)
- 【BZOJ1014】火星人prefix Splay 字符串Hash
- 【BZOJ1014】【tyvj3486】火星人prefix,Splay+字符串hash
- 【BZOJ1014】[JSOI2008]火星人prefix
- [BZOJ1014] [JSOI2008]火星人prefix
- bzoj1014 [JSOI2008]火星人prefix
- 转载:数据库相关中间件
- 搭建Hadoop集群
- CREST: Convolutional Residual Learning for Visual Tracking
- 深入理解Java中的final关键字
- acm 输入输出处理入门 A+B(I) C++实现
- bzoj1014 [JSOI2008]火星人prefix ( splay + hash )
- Python 修改目录下所有文件名为MD5
- hdu1559 最大子矩阵
- 什么是docker
- 作业
- lua源码阅读(7)-指令
- Django-paginator(分页)
- 转载:操作系统为什么要分用户态和内核态
- bzoj 1996(区间dp)