【题目链接】

 

    http://www.lydsy.com/JudgeOnline/problem.php?id=1014

 

【题意】

 

    给定一个字符串,要求提供修改一个字符,插入一个字符,查询两个后缀LCP的功能。

 

【思路】

 

  splay维护字符串的哈希值。因为要提供区间,splay采用先查找后调整至根的写法。

    一个结点的hash值为:

        ch[0]->h * X^(ch[1]->s+1)+v * X^(ch[1]->s)+ch[1]->h

    对于一个询问每次二分长度,提取区间后比较hash值即可。

    需要注意的是splay要提前在区间的左右两边各加上一个节点,不然会调用到null。

    ull自然溢出相当于模2^64。

 

【代码】

 

  1 #include<set>
  2 #include<cmath>
  3 #include<queue>
  4 #include<vector>
  5 #include<cstdio>
  6 #include<cstring>
  7 #include<iostream>
  8 #include<algorithm>
  9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
 11 using namespace std;
 12 
 13 typedef long long ll;
 14 typedef unsigned long long ull;
 15 const int N = 5e5+10;
 16 const int X = 27;
 17 
 18 ll read() {
 19     char c=getchar();
 20     ll f=1,x=0;
 21     while(!isdigit(c)) {
 22         if(c=='-') f=-1; c=getchar();
 23     }
 24     while(isdigit(c))
 25         x=x*10+c-'0',c=getchar();
 26     return x*f;
 27 }
 28 
 29 char s[N];
 30 int n,q;
 31 ull powx[N];
 32 
 33 struct Node* null;
 34 struct Node {
 35     int s,v; ull h;
 36     Node* ch[2];
 37     int cmp(int k) {
 38         if(k==ch[0]->s+1) return -1;
 39         return k<=ch[0]->s? 0:1;
 40     }
 41     void init(int x) {
 42         v=h=x; s=1;
 43         ch[0]=ch[1]=null;
 44     }
 45     void maintain() {
 46         s=ch[0]->s+ch[1]->s+1;
 47         h=ch[0]->h*powx[ch[1]->s+1]+v*powx[ch[1]->s]+ch[1]->h;
 48     }
 49 } *root,nodepool[N]; int nodesz=0;
 50 
 51 void rot(Node* &o,int d) {
 52     Node* k=o->ch[d^1]; o->ch[d^1]=k->ch[d]; k->ch[d]=o;
 53     o->maintain(),k->maintain(); o=k;
 54 }
 55 void splay(Node*& o,int k) {
 56     int d=o->cmp(k);
 57     if(d==1) k-=o->ch[0]->s+1;
 58     if(d!=-1) {
 59         Node* p=o->ch[d];
 60         int d2=p->cmp(k),k2=(d2==0?k:k-p->ch[0]->s-1);
 61         if(d2!=-1) {
 62             splay(p->ch[d2],k2);
 63             if(d==d2) rot(o,d^1); else rot(o->ch[d],d);
 64         }
 65         rot(o,d^1);
 66     }
 67 }
 68 //return range (l,r]
 69 //加过点后 s[l,r]=range(l,r+1)
 70 Node*& range(int l,int r) {
 71     splay(root,l);
 72     splay(root->ch[1],r-l+1);
 73     return root->ch[1]->ch[0];
 74 }
 75 
 76 Node* build(int l,int r)
 77 {
 78     if(r<l) return null;
 79     int mid=l+r>>1;
 80     Node* o=&nodepool[++nodesz];
 81     o->init(s[mid]-'a'+1);
 82     o->ch[0]=build(l,mid-1);
 83     o->ch[1]=build(mid+1,r);
 84     o->maintain();
 85     return o;
 86 }
 87 void insert(int p,int v) 
 88 {
 89     splay(root,p+1);
 90     Node* o=&nodepool[++nodesz]; 
 91     o->init(v);
 92     o->ch[0]=root->ch[0]; o->ch[1]=null;
 93     o->maintain();
 94     root->ch[0]=o; root->maintain();
 95 }
 96 void change(int p,int v)
 97 {
 98     splay(root,p);
 99     root->v=v;
100     root->maintain();
101 }
102 
103 int main()
104 {
105     //freopen("in.in","r",stdin);
106     //freopen("out.out","w",stdout);
107     null=new Node();
108     scanf("%s",s+1);
109     int n=strlen(s+1);
110     s[0]='z'+1; s[++n]='z'+1; s[n+1]='\0';
111     scanf("%d",&q);
112     powx[0]=1;
113     FOR(i,1,n+q) powx[i]=powx[i-1]*X;
114     root=build(0,n);
115     while(q--) {
116         char op[2],val[2]; 
117         int x,y;
118         scanf("%s%d",op,&x);
119         if(op[0]=='R') {
120             scanf("%s",val);
121             change(x+1,val[0]-'a'+1);
122         } else 
123         if(op[0]=='I') {
124             scanf("%s",val);
125             insert(x+1,val[0]-'a'+1);
126         } else {
127             scanf("%d",&y);
128             int len=root->s,L=0,R=0;
129             R=min(len-y-1,len-x-1);
130             while(L<R) {
131                 int M=L+(R-L+1)/2;
132                 ull H=range(x,x+M)->h;
133                 H-=range(y,y+M)->h;
134                 if(!H) L=M; else R=M-1;
135             }
136             printf("%d\n",L);
137         }
138         
139     }
140     return 0;
141 }