• Codeforces 1037H Security sam+线段树合并


    Codeforces 1037H Security

    题意

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

    (nle 10^5,qle 2cdot 10^5,sum |s|le 2cdot 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
    ",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;
    }
    
  • 相关阅读:
    关于三次握手与四次挥手你要知道这些
    seafile看不见repo报500错误的解决方法
    VMWare Workstation 配置docker多macvlan网络方法
    利用Python3的dpkt库进行ARP扫描
    关于LAMP配置Let’s Encrypt SSL证书
    OpenSSL生成CA证书及终端用户证书
    CentOS7.2安装Vim8和YouCompleteMe
    CentOS 7.2安装Jenkins自动构建Git项目
    CentOS 7.2 安装Gerrit 2.14.6
    CentOS7.2编译GCC7.3
  • 原文地址:https://www.cnblogs.com/xyq0220/p/13887952.html
Copyright © 2020-2023  润新知