bzoj 1014 [JSOI2008]火星人prefix——splay+哈希
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1014
用splay维护字符串,每个点记录子树的哈希值,然后二分查询。
二分不是把两个点的哈希值拿出来二分!因为取模了所以不能还原;因为splay维护了字符串,所以二分答案后把对应一段转出来看看哈希值一不一样就行了。
如果一开始不是用给出的序列直接建一个树(就是递归 l,mid-1 和 mid+1,r 那样的),而是像我一开始一样一个一个往进插入的话,不知为何过不了呢。
有些卡时间。据说%mod会T,于是用 unsigned long long 自然溢出。
用 nxt 找后继的时候要先把对象旋转到根才行。
幂也要预处理以防超时。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #define ll unsigned long long using namespace std; const int N=2e5+5,base=27; int n,tot,c[N][2],fa[N],rt,siz[N]; ll val[N],sm[N],pw[N]; char ch[N]; int init() { pw[0]=1; for(int i=1;i<=N-5;i++) pw[i]=pw[i-1]*base; } void pshp(int cr) { int ls=c[cr][0],rs=c[cr][1]; siz[cr]=siz[ls]+siz[rs]+1; val[cr]=(val[rs]*base+sm[cr])*pw[siz[ls]]+val[ls]; } void rotate(int x,int &k) { int y=fa[x],z=fa[y]; if(y==k) k=x; else c[z][y==c[z][1]]=x; int d=(x==c[y][1]); fa[x]=z; fa[y]=x; fa[c[x][!d]]=y; c[y][d]=c[x][!d]; c[x][!d]=y; pshp(y); pshp(x); } void splay(int x,int &k) { while(x!=k) { int y=fa[x],z=fa[y]; if(y!=k) { if((x==c[y][0])^(y==c[z][0])) rotate(x,k); else rotate(y,k); } rotate(x,k); } } int find(int p) { int cr=rt; while(cr) { if(siz[c[cr][0]]+1==p)return cr; else if(siz[c[cr][0]]+1<p) { p-=siz[c[cr][0]]+1; cr=c[cr][1]; } else cr=c[cr][0]; } } int nxt(int cr) { cr=c[cr][1]; while(c[cr][0]) cr=c[cr][0]; return cr; } void insert(int p,int v) { int d=find(p); splay(d,rt); int x=nxt(d); splay(x,c[rt][1]); siz[++tot]=1; val[tot]=sm[tot]=v; fa[tot]=x; c[x][0]=tot; pshp(x); pshp(d); } void mdfy(int p,int v) { int d=find(p); splay(d,rt); sm[d]=v; pshp(d); } ll cz(int u,int v) { splay(u,rt); int k=find(v); splay(k,c[rt][1]); return val[c[k][0]]; } void query(int u,int v) { int l=1,r=min(tot-u,tot-v); int ans=0; int x=find(u-1), y=find(v-1); while(l<=r) { int mid=l+r>>1; if(cz(x,u+mid)==cz(y,v+mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); } void build(int l,int r,int lst,bool fx) { if(l>r) return; int mid=l+r>>1; int cr=++tot; fa[cr]=lst; c[lst][fx]=cr; sm[cr]=ch[mid]-'a'+1; if(l==r) {val[cr]=sm[cr]; siz[cr]=1; return;} build(l,mid-1,cr,0); build(mid+1,r,cr,1); pshp(cr); } int main() { init(); scanf("%s",ch+2); n=strlen(ch+2); ch[1]='a'; ch[n+2]='a'; n+=2; build(1,n,0,0); rt=1; c[0][0]=0; scanf("%d",&n); for(int i=1,x,d;i<=n;i++) { cin>>ch[0]; if(ch[0]=='I') { scanf("%d %c",&x,&ch[1]); d=ch[1]-'a'+1; insert(x+1,d); } if(ch[0]=='R') { scanf("%d %c",&x,&ch[1]); d=ch[1]-'a'+1; mdfy(x+1,d); } if(ch[0]=='Q') { scanf("%d%d",&x,&d); query(x+1,d+1); } } return 0; }