AOJ2644 - Longest Match

ratingを上げるために新しい問題を解こうと思ったら、ちょうど練習したかったsuffix arrayの問題がありました。例外処理(文字列が存在しない場合)が難しく、とりあえず思いつく限りの条件を列挙したのでコードは汚いです。

問題:
Longest Match | Aizu Online Judge

問題概要:
文字列Sとm個のクエリが与えられる。それぞれのクエリについて文字列xと文字列yが与えられ、xで始まりyで終わるSの部分文字列の長さの最大値を求める。

解法:
suffix arrayとsegment treeを用いました。

コード:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<queue>
#define mp make_pair
#define pb push_back
#define INF 100000005
#define rep(i,n) for(int i = 0;i < n;i++)
using namespace std;
int sa[200005],rk[200005],tmp[200005];

string S,T;
int kk;
int len;

int sg[2][1<<19];//[0]が最小値、[1]が最大値を保持

bool compare_sa(int i,int j){
    if(rk[i]!=rk[j]){
        return rk[i]<rk[j];
    }else{
        int ri = (i+kk<len)?rk[i+kk]:-1;
        int rj = (j+kk<len)?rk[j+kk]:-1;
        return ri<rj;
    }
}

void construct_sa(){
    len=(int)S.length();
    rep(i,len+1){
        sa[i]=i;
        rk[i]=(i<len)?S[i]:-1;
    }
    for(kk=1;kk<=len;kk*=2){
        sort(sa,sa+len+1,compare_sa);
        tmp[sa[0]]=0;
        for(int i = 1;i<=len;i++){
            tmp[sa[i]]=tmp[sa[i-1]]+(compare_sa(sa[i-1],sa[i])?1:0);
        }
        rep(i,len+1){
            rk[i]=tmp[i];
        }
    }
}

void update(bool f,int p,int x){//sg[f]のp番目にxを挿入
    p+=(1<<18)-1;
    sg[f][p]=x;
    while(p>0){
        p=(p-1)/2;
        sg[f][p]=(f?max(sg[f][p],x):min(sg[f][p],x));
    }
}

int query(bool f,int a,int b,int k,int l,int r){
    if(r<=a||b<=l)return f?-INF:INF;
    if(a<=l&&r<=b)return sg[f][k];
    else{
        int mid = (l+r)/2;
        int vl=query(f,a,b,k*2+1,l,mid);
        int vr=query(f,a,b,k*2+2,mid,r);
        int ret=(f?max(vl,vr):min(vl,vr));
        return ret;
    }
}

int query(bool f,int a,int b){
    return query(f,a,b,0,0,(1<<18));
}

int search(string t){
    int a=0,b=len+1;
    while(b-a>1){
        int c=(a+b)/2;
        if(S.compare(sa[c],T.length(),T)<0)a=c;
        else b=c;
    }
    return b;
}

int main(){
    cin>>S;
    rep(i,1<<19){
        sg[0][i]=INF;
        sg[1][i]=-INF;
    }
    construct_sa();
    rep(i,len+1){
        update(0,i,sa[i]);
        update(1,i,sa[i]);
    }

    int testcase;
    cin>>testcase;
    while(testcase--){
        int checkl;
        bool flag = 1;
        int ansl,ansr;
        int right,left;
        cin>>T;
        checkl=(int)T.length();
        left = search(T);
        T[T.length()-1]+=1;
        right=search(T);
        if(left==right)flag=0;
        ansl=query(0,left,right);

        cin>>T;
        left = search(T);
        T[T.length()-1]+=1;
        right=search(T);
        if(left==right)flag=0;
        ansr=query(1,left,right)+(int)T.length();
        if(ansl>len||ansl>=ansr)flag=0;
        if(ansr-ansl<checkl)flag=0;
        if(flag){
            cout<<ansr-ansl<<endl;
        }else{
            cout<<0<<endl;
        }
    }
}