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/)。未经允许,请勿转载。
posted @ 2018-09-04 00:06  粉兔  阅读(260)  评论(0编辑  收藏  举报