Codeforces 1037H Security sam+线段树合并

Codeforces 1037H Security

题意

给一个长度为\(n\)的字符串\(s\)\(q\)次询问,每次询问给出两个整数\(l,r\)和一个字符串\(x\),你要在区间\([l,r]\)中找到\(s\)的一个子串满足其字典序大于\(x\),输出满足条件的子串中字典序最小的子串,找不到输出\(-1\)

\(n\le 10^5,q\le 2\cdot 10^5,\sum |s|\le 2\cdot 10^5\)

分析

用线段树维护后缀自动机上每个点\(u\)的终点集合\(endpos(u)\),对于每个询问,枚举\(x\)的每个前缀在\(sam\)上转移,再尝试去在后面添加一个更大的字符\(c\),判断转移到的点的\(endpos\)集合中有没有\([l,r]\)中的点,有则更新答案。

Code

#include<bits/stdc++.h>
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define per(i,n,x) for(int i=n;i>=x;i--)
#define sz(a) int(a.size())
#define rson mid+1,r,rs[p]
#define pii pair<int,int>
#define lson l,mid,ls[p]
#define ll long long
#define pb push_back
#define mp make_pair
#define se second
#define fi first
using namespace std;
const double eps=1e-8;
const int mod=1e9+7;
const int N=4e5+10;
const int inf=1e9;
int n,m;
char s[N],t[N];
vector<int>g[N];
struct SegmentTree{
    int tr[N*40],ls[N*40],rs[N*40],tot;
    void up(int x,int l,int r,int &p){
        if(!p) p=++tot;
        tr[p]++;
        if(l==r) return;
        int mid=l+r>>1;
        if(x<=mid) up(x,lson);
        else up(x,rson);
    }
    int merge(int x,int y,int l,int r){
        if(!x||!y) return x+y;
        int o=++tot,mid=l+r>>1;
        if(l==r) tr[o]=tr[x]+tr[y];
        else{
            ls[o]=merge(ls[x],ls[y],l,mid);
            rs[o]=merge(rs[x],rs[y],mid+1,r);
            tr[o]=tr[ls[o]]+tr[rs[o]];
        }
        return o;
    }
    int qy(int dl,int dr,int l,int r,int p){
        if(!p||l>r) return 0;
        if(l==dl&&r==dr) return tr[p];
        int mid=l+r>>1;
        if(dr<=mid) return qy(dl,dr,lson);
        else if(dl>mid) return qy(dl,dr,rson);
        else return qy(dl,mid,lson)+qy(mid+1,dr,rson);
    }
}seg;
struct SAM{
    int last,cnt;int ch[N][26],fa[N],len[N],rt[N];
    void insert(int c,int pos){
        int p=last,np=++cnt;last=np;len[np]=len[p]+1;
        for(;p&&!ch[p][c];p=fa[p]) ch[p][c]=np;
        if(!p) fa[np]=1;
        else {
            int q=ch[p][c];
            if(len[q]==len[p]+1) fa[np]=q;
            else  {
                int nq=++cnt;len[nq]=len[p]+1;
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
            }
        }
        seg.up(pos,1,n,rt[np]);
    }
    void init(){
        last=cnt=1;
    }
    void dfs(int u){
        for(int x:g[u]){
            dfs(x);
            rt[u]=seg.merge(rt[u],rt[x],1,n);
        }
    }
    void gao(){
        for(int i=2;i<=cnt;i++) g[fa[i]].pb(i);
        dfs(1);
    }
    void solve(int l,int r){
        int u=1;
        t[m+1]='a'-1;
        pii ans=mp(-1,-1);
        for(int i=1;i<=m+1;i++){
            for(int j=t[i]-'a'+1;j<26;j++){
                int x=ch[u][j];
                if(!x) continue;
                int pos=seg.qy(l+i-1,r,1,n,rt[x]);
                if(pos){
                    ans=mp(i,j);
                    break;
                }
            }
            if(i==m+1||!ch[u][t[i]-'a']) break;
            u=ch[u][t[i]-'a'];
        }
        if(ans==mp(-1,-1)) puts("-1");
        else{
            t[ans.fi]=0;
            printf("%s%c\n",t+1,ans.se+'a');
        }
    }
}sam;
int main(){
    scanf("%s",s+1);
    n=strlen(s+1);
    sam.init();
    for(int i=1;i<=n;i++) sam.insert(s[i]-'a',i);
    sam.gao();
    int q,l,r;
    scanf("%d",&q);
    while(q--){
        scanf("%d%d",&l,&r);
        scanf("%s",t+1);
        m=strlen(t+1);
        sam.solve(l,r);
    }
    return 0;
}
posted @ 2020-10-27 22:08  xyq0220  阅读(89)  评论(0编辑  收藏  举报