思路:
1.如果没有操作I,也就是insert操作,则很容易想到用后缀数组处理,直接计算lcp(i,j)即可,要注意的是用rmq计算lcp[i][j]的时候,如果i==j,要做特殊处理!
2.题目有个很容易误解的地方,就是Q操作的时候是对原始下标,而I操作的p是插入后的下标
3.计算Q(i,j)的时候,首先计算lcp(i,j),
1)如果lcp(i,j)大于离i,j最近的插入字符到i,j的距len, 则定位到i+len, j+len, 比较i+len,j+len处的插入字符,从而问题转换为lcp(i',j'),重复即可。
2)如果lcp(i,j)小于等于len,则答案即为lcp(i,j);
- #include <iostream>
- #include <string>
- #include <algorithm>
- using namespace std;
- #define Min(a,b) (a)<(b)?(a):(b)
- const int N = 51000;
- const int M = 260;
- int n, m;
- char s[N];
- struct
- {
- char c;
- int p;
- }si[M];
- int cnt[N], mem[4][N], *rank, *nrank, *sa, *nsa, lcp[17][N];
- // lcp[i][j]: longest commen prefix ( suffix(sa[k+1]), suffix(sa[k]) ) j <= k < j+2^i
- void radix_sort()
- {
- int i, j, k;
- rank = mem[0];
- nrank = mem[1];
- sa = mem[2];
- nsa = mem[3];
- for(i = 0; i < n; i++) cnt[s[i]]++;
- for(i = 1; i < M; i++) cnt[i] += cnt[i-1];
- for(i = n-1; i >= 0; i--) sa[--cnt[s[i]]] = i;
- for(rank[0]=0, i=1; i < n; i++)
- {
- rank[sa[i]] = rank[sa[i-1]];
- if(s[sa[i]]!=s[sa[i-1]]) rank[sa[i]]++;
- }
- for(k = 1; k<n && rank[sa[n-1]] < n-1; k*=2)
- {
- for(i = 0; i < n; i++) cnt[rank[sa[i]]] = i+1;
- for(i = n-1; i >= 0; i--) if(sa[i]-k>=0)
- nsa[--cnt[rank[sa[i]-k]]] = sa[i]-k;
- // max(sa[i]-k)=n-k-1 , therefore i = n-k;
- for(i = n-k; i < n; i++)
- nsa[--cnt[rank[i]]] = i;
- for(nrank[nsa[0]], i=1; i < n; i++)
- {
- nrank[nsa[i]] = nrank[nsa[i-1]];
- if(rank[nsa[i]] != rank[nsa[i-1]]
- || rank[nsa[i]+k] != rank[nsa[i-1]+k])
- nrank[nsa[i]]++;
- }
- swap(rank, nrank);
- swap(sa, nsa);
- }
- }
- void print()
- {
- for(int i=0;i<n;i++) printf("%d %s/n", sa[i], s + sa[i]);puts("");
- puts(s);for(int i=0;i<n;i++) printf("%d ", rank[i]);puts("");
- }
- void get_lcp_rmq()
- {
- int i, j, k;
- for(i=0,k=0; i<n; i++)
- {
- if(rank[i]==n-1) lcp[0][rank[i]]=k=0;
- else
- {
- if(k>0)k--;
- j = sa[rank[i]+1];
- for(;s[i+k]==s[j+k];k++) ;
- lcp[0][rank[i]]=k;
- }
- }
- for(i=0,k=1; k<n; k*=2, i++)
- {
- for(j = 0; j+k < n; j++)
- lcp[i+1][j] = Min(lcp[i][j], lcp[i][j+k]);
- }
- }
- int rmq(int a, int b)
- {
- int i, j, k;
- a = rank[a];
- b = rank[b];
- if(a>b) swap(a,b);
- int t=b-a;
- for(i=0,k=1; 2*k<t; i++,k*=2) ;
- return Min(lcp[i][a], lcp[i][b-k]); // not b-k+1
- // lcp[0][i]: LCP(i,i+1)
- }
- /*
- aaaaaaaa
- I a 2
- I b 3
- Q 1 3
- */
- int query(int a, int b)
- {
- int i,j,k;
- int mi, ret=0;
- int x, y, t;
- char c1, c2;
- for(x = 0; si[x].p <= a; x++);
- for(y = 0; si[y].p <= b; y++);
- if(a==b) return n-a+m-x-2;
- while(1)
- {
- k = rmq(a, b);
- i = si[x].p-a;
- j = si[y].p-b;
- t = Min(k, Min(i,j));
- ret+=t; a+=t; b+=t;
- if(t==i || t==j)
- {
- while(si[x].p==a&&si[y].p==b)
- {
- if(si[x].c==si[y].c) x++,y++,ret++;
- else return ret;
- }
- while(si[x].p==a)
- {
- if(si[x].c==s[b]) x++,b++,ret++;
- else return ret;
- }
- while(si[y].p==b)
- {
- if(si[y].c==s[a]) y++,a++,ret++;
- else return ret;
- }
- }
- else return ret;
- }
- return ret;
- }
- void insert(char ch, int pos)
- {
- int i;
- for(i = 0; i < m; i++)
- {
- if(si[i].p>=pos)break;
- else pos--;
- }
- if(pos >= n) pos = n-1;
- int j=i;
- for(i = m++; i > j; i--) si[i] = si[i-1];
- si[j].c = ch;
- si[j].p = pos;
- }
- int main()
- {
- int i, j, k;
- char cmd[10];
- scanf("%s", s);
- n = strlen(s);
- s[n++]=0;
- radix_sort();
- get_lcp_rmq();
- si[0].c = 0;
- si[0].p = N;
- m = 1;
- scanf("%d", &k);
- while(k--)
- {
- scanf("%s", cmd);
- if(cmd[0]=='Q')
- {
- scanf("%d%d", &i, &j);
- printf("%d/n", query(i-1,j-1));
- }
- else
- {
- scanf("%s%d", cmd, &i);
- insert(cmd[0], i-1);
- }
- }
- return 0;
- }