hdoj 5008 后缀数组+RMQ+二分

hdoj 5008

题意:给一个字符串,问该字符串第k个子串的最小字典序位置。其中k需要L xor R xor V求得,L R是前一个询问的子串位置,说白了就是强制在线。

思路:先是后缀数组处理出子串去重后的编号,然后先求得第k个子串的位置i,因为这个位置只是后缀数组中第一次出现的位置,而不一定是原字符串中最左边的位置,所以真正的位置可能在i的左边或右边。如果遍历去找肯定会超时,但是我们可以二分。

假设第k个子串的长度为d,起始下标为i,真实下标为j,那么i到j的公共前缀一定大于等于d,即height[i] >= d, height[i + 1] >=d ....height[j]>=d(j也可能在i的左边),那么我们只要保证min(height[i],height[i + 1]...height[j])>= d就可以了,这就用到了RMQ,我这里是用线段树实现的。

这样就可以求出含有公共前缀的最大范围L和R(L<=i, R>=i)。

然后只要求出[L,R]中最小的sa就可以了,这里就用到了另一个RMQ。

所以我们一共需要两个RMQ,一个用来查询区间最小公共前缀长度(height),一个用来查询区间最小后缀起始位置(sa)。

另外还有一些细节,后缀数组得到的答案L,R是以0开始的,xor和输出答案的时候记得加1(我就这里wa了好多次。。。TAT),还有k、v是long long。

#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int MAXN = 100010;
int sa[MAXN];
int t1[MAXN],t2[MAXN],c[MAXN];
int Rank[MAXN],height[MAXN];
void build_sa(int s[],int n,int m)
{
    int i,j,p,*x=t1,*y=t2;
    for(i=0;i<m;i++)c[i]=0;
    for(i=0;i<n;i++)c[x[i]=s[i]]++;
    for(i=1;i<m;i++)c[i]+=c[i-1];
    for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(j=1;j<=n;j<<=1)
    {
        p=0;
        for(i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;i<m;i++)c[i]=0;
        for(i=0;i<n;i++)c[x[y[i]]]++;
        for(i=1;i<m;i++)c[i]+=c[i-1];
        for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];
        swap(x,y);
        p=1;x[sa[0]]=0;
        for(i=1;i<n;i++)
            x[sa[i]]=y[sa[i-1]]==y[sa[i]] && y[sa[i-1]+j]==y[sa[i]+j]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}
void getHeight(int s[],int n)
{
    int i,j,k=0;
    for(i=0;i<=n;i++)Rank[sa[i]]=i;
    for(i=0;i<n;i++)
    {
        if(k)k--;
        j=sa[Rank[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[Rank[i]]=k;
    }
}

int seq[MAXN];
void suffix_array(char str[]){
    int len = strlen(str);
    for(int i = 0; i <= len; i++) seq[i] = str[i];
    seq[len] = 0;
    build_sa(seq, len + 1, 128);
    getHeight(seq, len);
}
char str[MAXN];
//==================================================================================
long long sum[MAXN], len;
struct Tree{
    int l, r, val[2];
}tree[MAXN * 4];//0 height 1 sa
int cnt = 0;
void buildtree(int rt, int l, int r) {
    tree[rt].l = l, tree[rt].r = r;
    if(l == r) {
        tree[rt].val[0] = height[cnt];
        tree[rt].val[1] = sa[cnt++];
        return ;
    }
    int mid = (l + r) / 2;
    buildtree(rt * 2, l, mid);
    buildtree(rt * 2 + 1, mid + 1, r);
    tree[rt].val[0] = min(tree[rt * 2].val[0], tree[rt * 2 + 1].val[0]);
    tree[rt].val[1] = min(tree[rt * 2].val[1], tree[rt * 2 + 1].val[1]);
}
int query(int rt, int l, int r, int id) {
    if(tree[rt].l == l && tree[rt].r == r) {
        return tree[rt].val[id];
    }
    int mid = (tree[rt].l + tree[rt].r) / 2;
    if(l > mid) return query(rt * 2 + 1, l, r, id);
    else if(r <= mid) return query(rt * 2, l, r, id);
    else {
        return min(query(rt * 2, l, mid, id), query(rt * 2 + 1, mid + 1, r, id));
    }
}
int bsl(int x, int LEN) {
    int l = 1, r = x - 1, mid, ret = x;
    while(l <= r) {
        mid = (l + r) >> 1;
        if(query(1, mid + 1, x, 0) >= LEN) {
            ret = mid, r = mid - 1;
        }
        else l = mid + 1;
    }
    return ret;
}
int bsr(int x, int LEN) {
    int l = x + 1, r = len, mid, ret = x;
    while(l <= r) {
        mid = (l + r) >> 1;
        if(query(1, x + 1, mid, 0) >= LEN) {
            ret = mid, l = mid + 1;
        }
        else r = mid - 1;
    }
    return ret;
}
main() {
    int n;
    while(~scanf("%s", str)) {
        len = strlen(str);
        suffix_array(str);
        memset(tree, 0, sizeof tree);
        cnt = 1;
        buildtree(1, 1, len);
        for(int i = 1; i <= len; i++) {
            sum[i] = sum[i - 1] + len - sa[i] - height[i];
        //    printf("sa[%d] = %d height[%d] = %d\n", i, sa[i], i, height[i]);

        }
        long long l = 0, r = 0, v, k;
        scanf("%d", &n);
        while(n--) {
            scanf("%I64d", &v);
            v ^= l ^ r;
            k = v + 1;
    //        printf("k = %I64d\n", k);
            if(k > sum[len]) {
                puts("0 0");
                l = r = 0;
                continue;
            }
            int t = lower_bound(sum + 1, sum + 1 + len, k) - sum;
            l = sa[t], r = len - (sum[t] - k + 1);
            int d = r - l + 1;
            int L = bsl(t, d), R = bsr(t, d);
      //      printf("L = %d R = %d\n", L, R);
            int ans = query(1, L, R, 1);
      //      printf("l = %d\n", ans);
            l = ans + 1, r = l + d - 1;
            printf("%I64d %I64d\n", l, r);
        }
    }
}


1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。、可私 6信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看README.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 、可私信6博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值