您的位置:首页 > 其它

POJ 2758 后缀数组

2008-08-04 19:15 459 查看
思路:

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
;

struct

{

char c;

int p;

}si[M];

int cnt
, mem[4]
, *rank, *nrank, *sa, *nsa, lcp[17]
;

// 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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: