bzoj 1014: 洛谷 P4036: [JSOI2008]火星人
题目传送门:洛谷P4036。
题意简述:
有一个字符串,支持插入字符,修改字符。
每次需要查询两个后缀的LCP长度。
最终字符串长度\(\le 100,\!000\),修改和询问的总个数\(\le 150,\!000\),查询操作\(\le 10,\!000\)。
题解:
由后缀和LCP可以想到后缀数组或后缀自动机,但是它们都无法插入或修改。
考虑到LCP可以通过二分+哈希的方式来计算,考虑维护区间的哈希值。
这里使用平衡树无旋Treap来维护区间的哈希值。
一次修改\(O(\log n)\),一次询问\(O(\log^2 n)\)。
bzoj时限略卡,用了自然溢出才过。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Bse 19260817u 4 unsigned Pow[100005]; 5 6 char Str[100005]; 7 int N,Q; 8 int ls[100005],rs[100005],siz[100005],pri[100005],val[100005],cnt,Root; 9 unsigned ha[100005]; 10 11 unsigned ran(){static unsigned x=23333;return x^=x<<13,x^=x>>17,x^=x<<5;} 12 13 void combine(int id){ 14 siz[id]=siz[ls[id]]+1+siz[rs[id]]; 15 ha[id]=Pow[siz[rs[id]]+1]*ha[ls[id]]+Pow[siz[rs[id]]]*val[id]+ha[rs[id]]; 16 } 17 18 int Merge(int rt1,int rt2){ 19 if(!rt1) return rt2; 20 if(!rt2) return rt1; 21 if(pri[rt1]>=pri[rt2]){ 22 rs[rt1]=Merge(rs[rt1],rt2); 23 combine(rt1); 24 return rt1; 25 } 26 else{ 27 ls[rt2]=Merge(rt1,ls[rt2]); 28 combine(rt2); 29 return rt2; 30 } 31 } 32 33 void Split(int rt,int k,int&rt1,int&rt2){ 34 if(!rt) {rt1=rt2=0; return;} 35 if(k<=siz[ls[rt]]){ 36 Split(ls[rt],k,rt1,rt2); 37 ls[rt]=rt2; 38 combine(rt); 39 rt2=rt; 40 } 41 else{ 42 Split(rs[rt],k-siz[ls[rt]]-1,rt1,rt2); 43 rs[rt]=rt1; 44 combine(rt); 45 rt1=rt; 46 } 47 } 48 49 void Insert(int pos,int v){ 50 val[++cnt]=v, ha[cnt]=v, pri[cnt]=ran(), siz[cnt]=1; 51 int rt1,rt2; 52 Split(Root,pos,rt1,rt2); 53 Root=Merge(Merge(rt1,cnt),rt2); 54 } 55 56 void Change(int pos,int v){ 57 int rt1,rt2,rt3,rt4; 58 Split(Root,pos-1,rt1,rt2); 59 Split(rt2,1,rt3,rt4); 60 val[rt3]=v; combine(rt3); 61 Root=Merge(Merge(rt1,rt3),rt4); 62 } 63 64 unsigned chk(int pos,int len){ 65 int rt1,rt2,rt3,rt4; 66 Split(Root,pos-1,rt1,rt2); 67 Split(rt2,len,rt3,rt4); 68 unsigned D=ha[rt3]; 69 Root=Merge(Merge(rt1,rt3),rt4); 70 return D; 71 } 72 73 int main(){ 74 Pow[0]=1; for(int i=1;i<=100000;++i) Pow[i]=Pow[i-1]*Bse; 75 scanf("%s",Str+1); 76 N=strlen(Str+1); 77 for(int i=1;i<=N;++i) 78 Insert(i-1,Str[i]); 79 scanf("%d",&Q); 80 for(int i=1;i<=Q;++i){ 81 int x,y; char opt[5]; 82 scanf("%s",opt); 83 if(*opt=='Q'){ 84 scanf("%d%d",&x,&y); 85 int l=1, r=N-max(x,y)+1, mid, ans=0; 86 while(l<=r){ 87 mid=l+r>>1; 88 if(chk(x,mid)==chk(y,mid)) ans=mid, l=mid+1; 89 else r=mid-1; 90 } 91 printf("%d\n",ans); 92 } 93 else if(*opt=='R'){ 94 scanf("%d%s",&x,opt); 95 Change(x,*opt); 96 } 97 else if(*opt=='I'){ 98 scanf("%d%s",&x,opt); 99 Insert(x,*opt); 100 ++N; 101 } 102 } 103 return 0; 104 } 105 106 // luogu P4036 - Fhq-Treap + hash. 18:20 ~ 19:03
来自 PinkRabbit 的博客园(https://www.cnblogs.com/PinkRabbit/p/9581990.html)。未经允许,请勿转载。