CCPC2019网络赛 array【后缀数组】【主席树】【线段树上二分】

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6703

#include <bits/stdc++.h>
#define rep(i, a, b) for(int i = (a); i <= (b); i++)
#define per(i, a, b) for(int i = (a); i >= (b); i++)
#define ls (o<<1)
#define rs (o<<1|1)
#define mid ((l+r)>>1)
using namespace std;

const int N = 1e5+1000;
const int SIZE = 256;
//-----------------------------------------------------
int cntA[N],cntB[N],sa[N],tsa[N],A[N],B[N],height[N],Rank[N],bucket[SIZE];
int n;
char s[N];

void get_SA(char *ch) {
    for(int i = 0; i < SIZE; i++) bucket[i] = 0;
    rep(i, 1, n) bucket[ch[i-1]]++;
    rep(i, 1, SIZE-1) bucket[i] += bucket[i-1];
    for(int i = n; i; i--) sa[bucket[ch[i-1]]--] = i;
    Rank[sa[1]] = 1;
    for(int i = 2; i <= n; i++) {
        Rank[sa[i]] = Rank[sa[i-1]];
        if(ch[sa[i]-1]!=ch[sa[i-1]-1]) Rank[sa[i]]++;
    }
    for(int l = 1;Rank[sa[n]] < n; l<<=1) {
        memset(cntA,0,sizeof(cntA));
        memset(cntB,0,sizeof(cntB));
        for(int i = 1; i <= n; i++) {
            cntA[A[i] = Rank[i]]++;
            cntB[B[i] = (i+l<=n) ? Rank[i+l]:0]++;
        }
        for(int i = 1; i <= n; i++) cntB[i] += cntB[i-1];
        for(int i = n; i; i--) tsa[cntB[B[i]]--] = i;
        for(int i = 1; i <= n; i++) cntA[i] += cntA[i-1];
        for(int i = n; i; i--) sa[cntA[A[tsa[i]]]--] = tsa[i];
        Rank[sa[1]] = 1;
        for(int i = 2; i <= n; i++) {
            Rank[sa[i]] = Rank[sa[i-1]];
            if(A[sa[i]] != A[sa[i-1]] || B[sa[i]] != B[sa[i-1]]) Rank[sa[i]]++;
        }
    }
    for(int i = 1, j=0; i <= n; i++) {
        if(j) j--;
        while(ch[i+j-1]==ch[sa[Rank[i]-1]+j-1]) j++;
        height[Rank[i]] = j;
    }
}
//-----------------------------------------------------
int mt[4*N];
void build(int o,int l,int r) {
    if(l==r) {mt[o]=height[l];return;}
    build(ls,l,mid);
    build(rs,mid+1,r);
    mt[o] = min(mt[ls],mt[rs]);
}
int getL(int o,int l,int r,int x) {
    if(l==r) return l;
    return mt[rs]<x?getL(rs,mid+1,r,x):getL(ls,l,mid,x);
}
int qL(int o,int l,int r,int ql,int qr,int x) {
    if(ql>qr) return -1;
    if(qr<l||r<ql) return -1;
    if(ql<=l&&r<=qr) return mt[o]<x?getL(o,l,r,x):-1;
    int t = qL(rs,mid+1,r,ql,qr,x);
    return t!=-1?t:qL(ls,l,mid,ql,qr,x);
}
int getR(int o,int l,int r,int x) {
    if(l==r) return l;
    return mt[ls]<x?getR(ls,l,mid,x):getR(rs,mid+1,r,x);
}
int qR(int o,int l,int r,int ql,int qr,int x) {
    if(ql>qr) return -1;
    if(qr<l||r<ql) return -1;
    if(ql<=l&&r<=qr) return mt[o]<x?getR(o,l,r,x):-1;
    int t = qR(ls,l,mid,ql,qr,x);
    return t!=-1?t:qR(rs,mid+1,r,ql,qr,x);
}
//-----------------------------------
struct TREE{
    int l,r,x;
}tree[N*30];
int tot,rt[N];
void insert(int &o,int l,int r,int data) {
    tree[++tot] = tree[o];
    o = tot;
    tree[o].x++;
    if(l==r) return;
    if(mid>=data) insert(tree[o].l,l,mid,data);
    else insert(tree[o].r,mid+1,r,data);
}
int query(int lo,int ro,int l,int r,int data) {
    if(l==r) return l;
    int k = tree[tree[ro].l].x-tree[tree[lo].l].x;
    if(k>=data) return query(tree[lo].l,tree[ro].l,l,mid,data);
    else return query(tree[lo].r,tree[ro].r,mid+1,r,data-k);
}
//----------------------------------------
int main() {
    //freopen("a.txt","r",stdin);
    ios::sync_with_stdio(0);
    int T;
    cin>>T;
    while(T--) {
        int q;
        cin>>n>>q;
        cin>>s;
        n = strlen(s);
        get_SA(s);
        tot = 0;
        rt[0] = 0;
        tree[0].l = tree[0].r = tree[0].x = 0;
        rep(i, 1, n) {
            rt[i] = rt[i-1];
            insert(rt[i],1,n,sa[i]);
        }
        build(1,1,n);
        rep(i, 1, q) {
            int l, r, k;
            cin>>l>>r>>k;
            int len = (r-l+1);
            int now = Rank[l];
            int R = qR(1,1,n,now+1,n,len);
            if(R==-1) R = n;
            else R--;
            int L = qL(1,1,n,1,now,len);

            int ans;
            if(k>R-L+1) ans = -1;
            else ans = query(rt[L-1],rt[R],1,n,k);
            cout<<ans<<endl;
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值