重复子串(string) - SAM - 启发式合并 - 线段树

题目大意:给一个字符串多次询问一个子串s的权值。一个字符串的权值定义为最长的出现了至少两次的子串的长度。 n , m 1 0 5 n,m\le10^5
题解:考虑把串反过来,建SAM。显然询问要先二分一波。
那就是求对应下标在某个区间内的点是否存在两个点其LCA的val大于等于二分的值。
考虑哪些点对有可能成为答案,显然如果有三个前缀下标a,b,c满足a<b<c(设ps(a)表示前缀a对应的节点),以及 L C A ( p s ( a ) , p s ( b ) ) = L C A ( p s ( a ) , p s ( c ) ) LCA(ps(a),ps(b))=LCA(ps(a),ps(c)) ,那么显然选择(a,c)一定不会比(a,b)优,因此启发式合并的求出所有有可能成为答案的点对,有 O ( n l g n ) O(nlgn) 个,所有可能成为答案的点形如(a,b,val)(假设a>b)。然后就是一个矩形询问最大值的问题,发现可以离线后直接线段树即可。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define ull unsigned lint
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;inline int gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    inline int inn() { int x,ch;while((ch=gc())<'0'||ch>'9');x=ch^'0';while((ch=gc())>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; }
    inline int instr(char *s) { int n=0,ch;while((ch=gc())<'a'||ch>'z');s[++n]=char(ch);while((ch=gc())>='a'&&ch<='z') s[++n]=char(ch);return n; }
}using INPUT_SPACE::inn;using INPUT_SPACE::instr;
namespace OUTPUT_SPACE{
    char ss[500000*15],tt[20];int ssl,ttl;inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
    inline int print(int x) { if(!x) ss[++ssl]='0';for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');for(;ttl;ttl--) ss[++ssl]=tt[ttl];return ss[++ssl]='\n'; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
const int N=200010,SIG=26,INF=INT_MAX/10;
vector<pii> ps[N],q[N];char s[N];int ans[N];
struct SAM{
    int val[N],fa[N],ch[N][SIG],rt,las,node_cnt,id[N];
    set<int> s[N];vector<int> g[N];
    inline int new_node(int v) { return val[++node_cnt]=v,node_cnt; }
    inline int _init() { return node_cnt=0,rt=las=new_node(0); }
    inline int extend(int w,int i)
    {
        int p=las,np=new_node(val[p]+1);
        while(p&&!ch[p][w]) ch[p][w]=np,p=fa[p];
        if(!p) fa[np]=rt;
        else{
            int q=ch[p][w],v=val[p]+1;
            if(val[q]==v) fa[np]=q;
            else{
                int nq=new_node(v);
                memcpy(ch[nq],ch[q],sizeof ch[q]);
                fa[nq]=fa[q],fa[q]=fa[np]=nq;
                while(p&&ch[p][w]==q) ch[p][w]=nq,p=fa[p];
            }
        }
        return id[las=np]=i;
    }
    inline int dfs(int x)
    {
        if(id[x]) s[x].insert(id[x]);s[x].insert(INF);
        Rep(i,g[x])
        {
            int y=g[x][i];dfs(y);
            if(s[x].size()<s[y].size()) s[x].swap(s[y]);
            if(s[y].empty()) continue;
            for(sit it=s[y].begin();it!=s[y].end();it++) if(*it!=INF)
            {
                sit it2=s[x].lower_bound(*it);
                if(*it2!=INF) ps[*it2].pb(mp(*it,val[x]));
                if(it2!=s[x].begin()) it2--,ps[*it].pb(mp(*it2,val[x]));
            }
            for(sit it=s[y].begin();it!=s[y].end();it++) s[x].insert(*it);set<int>().swap(s[y]);
        }
        return 0;
    }
    inline int solve() { rep(i,2,node_cnt) g[fa[i]].pb(i);return dfs(rt); }
}t;
struct segment{
    int v,l,r;segment *ch[2];
}*rt;
inline int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r,rt->v=0;
    if(l==r) return 0;int mid=(l+r)>>1;
    return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
inline int update(segment* &rt,int p,int v)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;rt->v=max(rt->v,v);
    if(l==r) return 0;return update(rt->ch[p>mid],p,v);
}
inline int query(segment* &rt,int s,int t)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return rt->v;int ans=0;
    if(s<=mid) ans=max(ans,query(rt->ch[0],s,t));
    if(mid<t) ans=max(ans,query(rt->ch[1],s,t));
    return ans;
}
inline int check(int l,int r,int x) { return query(rt,l+x-1,r)>=x; }
inline int query(int l,int r)
{
    int L=1,R=r-l+1;
    while(L<=R)
    {
        int mid=(L+R)>>1;
        if(check(l,r,mid)) L=mid+1;
        else R=mid-1;
    }
    return R;
}
int main()
{
    int n=inn(),m=inn(),r;instr(s),t._init();
    reverse(s+1,s+n+1);rep(i,1,n) t.extend(s[i]-'a',i);
    t.solve(),build(rt,1,n);
    rep(i,1,m) r=n-inn()+1,q[r].pb(mp(n-inn()+1,i));
    rep(i,1,n)
    {
        Rep(j,ps[i]) update(rt,ps[i][j].fir,ps[i][j].sec);
        Rep(j,q[i]) ans[q[i][j].sec]=query(q[i][j].fir,i);
    }
    rep(i,1,m) print(ans[i]);return Flush(),0;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/89336345
今日推荐