poj 2758 后缀数组
来源:互联网 发布:专业翻译软件 编辑:程序博客网 时间:2024/05/22 14:04
题意:
给一个字符串,提供两种操作,操作I:在 当前 第i个字符之前插入字符c;操作Q:求 原序列 后缀i,与后缀j的LCP,计算LCP时应把插入字符一起算上
思路:
确实没看出来这玩意能用后缀数组搞……
啊本题有好几个坑需要额外注意:
1. 插入时候的位置指的上当前序列;
2. 询问的位置指的是原序列,然后插入字符应计入比较;
3. 题目仅仅是说 Engligh Letter 而非 lower case letter,wa了半天才找到 - -|||;
4. I操作的步数非常少,最多200次
先抛开插入操作考虑询问操作,求一个序列任意两个后缀的LCP,显然后缀数组加RMQ,实现方式为对height数组做预处理,查询RMQ(rank[i],rank[j]);然后考虑插入,因为插入的操作数非常少,对于询问,可以先找到i和j的原序列LCP,再找到最近的一个插入在i,j后的字符距离i,j的位置k(这里找到最近的插入字符位置我是用set自带的平衡二叉树来加速查询),分情况讨论。
1. 如果LCP < k-1,显然插入字符对查询值无影响;
2. 如果LCP >= k-1,则从k位置开始,用t1,t2逐个指向当前序列中的字符,直至t1,,t2指向的均为原序列中的字符为止,然后递归查询t1,t2
本题在思路上不是特别麻烦,难点在看清题目的表述,以及实现能力上
#include <iostream> #include <algorithm> #include <stdio.h> #include <string.h> #include <vector> #include <set> using namespace std; const int MAXINT = 0x7fffffff; const int MAXSIZE = 5 * 1e4 + 100; vector<char> ins[MAXSIZE]; set<int> inset; #define rep(i,n) for(int i = 0; i < n; i++) int rk[MAXSIZE], sa[MAXSIZE], height[MAXSIZE], wa[MAXSIZE], res[MAXSIZE]; char w[MAXSIZE]; int len; void getSa(int up) { int *k = rk, *id = height, *r = res, *cnt = wa; rep(i, up) cnt[i] = 0; rep(i, len) cnt[k[i] = w[i]]++; rep(i, up) cnt[i + 1] += cnt[i]; for (int i = len - 1; i >= 0; i--) { sa[--cnt[k[i]]] = i; } int d = 1, p = 0; while (p < len){ for (int i = len - d; i < len; i++) id[p++] = i; rep(i, len) if (sa[i] >= d) id[p++] = sa[i] - d; rep(i, len) r[i] = k[id[i]]; rep(i, up) cnt[i] = 0; rep(i, len) cnt[r[i]]++; rep(i, up) cnt[i + 1] += cnt[i]; for (int i = len - 1; i >= 0; i--) { sa[--cnt[r[i]]] = id[i]; } swap(k, r); p = 0; k[sa[0]] = p++; rep(i, len - 1) { if (sa[i] + d < len && sa[i + 1] + d < len && r[sa[i]] == r[sa[i + 1]] && r[sa[i] + d] == r[sa[i + 1] + d]) k[sa[i + 1]] = p - 1; else k[sa[i + 1]] = p++; } if (p >= len) return; d <<= 1, up = p, p = 0; } } void getHeight() { int i, k, h = 0; rep(i, len) rk[sa[i]] = i; rep(i, len) { if (rk[i] == 0) h = 0; else { k = sa[rk[i] - 1]; if (h) h--; while (w[i + h] == w[k + h]) h++; } height[rk[i]] = h; } } void getSuffix() { len = strlen(w); int up = 0; rep(i, len) { w[i] = w[i] - 'A' + 1; up = up > w[i] ? up : w[i]; } w[len] = 0; getSa(up + 1); getHeight(); } int A[MAXSIZE]; int dmin[MAXSIZE][32]; void RMQ_init(int A[], int len){ //len 数组长度 for (int i = 0; i<len; ++i){ dmin[i][0] = A[i]; } for (int j = 1; (1 << j) <= len; ++j) for (int i = 0; i + (1 << j) - 1<len; ++i){ dmin[i][j] = min(dmin[i][j - 1], dmin[i + (1 << (j - 1))][j - 1]); } return; } int RMQ_min(int L, int R){ int k = 0; while (1 << (k + 1) <= R - L + 1) k++; return min(dmin[L][k], dmin[R - (1 << k) + 1][k]); } void sinsert(char c, int p){ bool flag = false; int cnt = 0; int k = -1; for (int i = 0;i<len;++i){ if (cnt + ins[i].size() < p - 1) cnt += ins[i].size(); else{ k = p - cnt - 2; if (ins[i].size() != 0){ ins[i].push_back(ins[i][ins[i].size()-1]); for (int j = ins[i].size() - 1; j > k + 1; --j) ins[i][j] = ins[i][j-1]; ins[i][k+1] = c; } else ins[i].push_back(c); inset.insert(i); //cout<<"Insert: "<<i<<endl; flag = true; break; } cnt++; } if (!flag){ if (cnt + ins[len].size() < p) ins[len].push_back(c); else{ k = p - cnt - 2; if (ins[len].size() != 0) for (int j = ins[len].size() - 1; j > k; --j) ins[len][j+1] = ins[len][j]; ins[len][k+1] = c; } inset.insert(len); //cout<<"Insert: "<<len<<endl; } } int query(int s1,int s2){ //cout<<"query: "<<s1<<" "<<s2<<endl; int ans = 0; if (s1 == s2){ for (int i = s1 + 1;i<len;++i){ ans+=ins[i].size(); } ans += len-s1; ans += ins[len].size(); return ans; } if (s1>s2) swap(s1,s2); int lcp; if (rk[s1] < rk[s2]) lcp = RMQ_min(rk[s1] + 1,rk[s2]); else lcp = RMQ_min(rk[s2] + 1,rk[s1]); ans = lcp; //cout<<"RMQ_lcp: "<<ans<<endl; int t = MAXINT; set<int>::iterator t1 = inset.upper_bound(s1); set<int>::iterator t2 = inset.upper_bound(s2); if (t1!=inset.end()) t = t < *t1-s1 ? t : *t1-s1; if (t2!=inset.end()) t = t < *t2-s2 ? t : *t2-s2; //cout<<"t: "<<t<<endl; if (lcp > t-1){ int i = s1 + t; int j = s2 + t; int i1 = 0, j1 = 0; ans = t; bool flag = true; while (flag && (ins[j].size() != 0 || ins[i].size() != 0)){ char ic, jc; if (i1 < ins[i].size()){ ic = ins[i][i1]; i1++; } else{ if (i == len) {flag = false;break;} ic = w[i]; i++; i1 = 0; } //cout<<"ic: "<<ic<<endl; if (j1 < ins[j].size()){ jc = ins[j][j1]; j1++; } else{ if (j == len) {flag = false;break;} jc = w[j]; j++; j1 = 0; } //cout<<"jc: "<<jc<<endl; if (ic == jc) ans++; else flag = false; //if (i == len || j == len) flag = false; } if (!flag) return ans; else { return ans+query(i,j); } } else return ans; } int main(){ int a,b; char temp[5]; scanf("%s",w); getSuffix(); RMQ_init(height,len); int n; scanf("%d",&n); for (int i=0;i<n;++i){ char c; scanf("%s",temp); if (temp[0] == 'Q'){ scanf("%d %d",&a,&b); int ans = query(a-1,b-1); printf("%d\n", ans); } else{ c = getchar(); c = getchar(); scanf("%d",&a); sinsert(c - 'A' + 1,a); } } return 0; }
阅读全文
0 0
- POJ 2758 后缀数组
- poj 2758(后缀数组)
- poj 2758 后缀数组
- poj 1743 后缀数组
- POJ 2774 后缀数组
- poj 2774 //后缀数组
- poj 3294 后缀数组
- poj 1743 后缀数组
- POJ 1743 (后缀数组)
- poj 3261 后缀数组
- poj 3693 (后缀数组)
- poj 3261 后缀数组
- poj 1743 后缀数组
- POJ 1743 后缀数组
- 【poj 3261】后缀数组
- 【poj 1743】后缀数组
- poj 3294 后缀数组
- poj 2774 后缀数组
- 常用的一些DOS命令
- VS2013+Ceres编译教程 Win7系统
- 数据库四种隔离级别
- tomcat 虚拟目录自定义404页面
- 国外Appleid共享
- poj 2758 后缀数组
- mysql常用命令详解
- JAVA附件上传之图片上传
- promise
- echarts的使用——vue
- 理解Python的With语句
- 编程实现库函数strcat
- Thinkphp框架加水印代码
- Fragment之我的解决方案:Fragmentation