タイトル
LOJ2720 PSlojデータでより良いです。
LuoguP4770
各二つの文字列SとTが与えられると、異なるサブストリングの列の番号の最初の質問は、第二のサブストリングではありません。
各クエリは、異なるSを与える、及びTは、(入力文字列の部分文字列は、入力を開始している\は([L、R] \ ) 記載しました)。
\(| S |、| T | <= 5 \ times10 ^ 5、\和| S | <= 10 ^ 6 \)
考え
データ構造、イデオロギー
- セグメントツリーの合併(永続化)
サフィックスオートマトン
真のアイデア
- いくつかの規則声明:endposのは、lenはリンクが接尾辞リンクを表し、表すノードの最長部分文字列の長さを示し、表しサブサフィックスオートマトンノードの終了位置を表します。
- まず、問題を単純化するために:決定することができ、各プレフィックス文字列Sのために考えてみましょうどのくらいの最長マッチした文字列のT. これより短いが、確かではないだろう。長いこの長さよりも、それは再利用ParentTreeすることが可能です。(長さのみ残りは、そのノードの接尾辞リンクポイントに乗り、自分でこのノードを取得します)
- きちんと、我々は、文字列S限り一致長Tサフィックスオートマトンは、その後、一致長サフィックスオートマトンを実行異なるサブストリングの数に載置されたSに実行されたことがわかりました。
- 例えば、ノード4 lenが8、リンクポイント3号、3号であり、lenが一致するノードの長さ4,4数3です。すなわち、長さ数3も3で一致させることができます。4による米国特許第4の答えでは、第3号で1件の回答を追加。(があるかもしれないので、他のノードは3ポイント、私たちは直接4を数えることができません)
- そして、質問の複数のセットを答える方法を検討してください。
- 私たちは、問題は、実行このステップの長さを合わせるTにSであることがわかりました。あなたが構築されたSAM Tを発見されますので。
- だから我々は、マッチングを実現するために始めSAM総入力文字列の使用を検討してください。
- (マッチしたノードときに我々が一致したときに、\(CNT \)ビット)は、実際の試合の長さは、ノードがendposの[L、R&LT]この範囲内で、LにendposのLから最も遠いです、距離、および\(CNT \)取る\(分\)の結果を。
以来、我々はそれがコレクションをendposの維持する必要があります。これは、ツリーラインと組み合わせることができます。しかし、我々は、(永続することができます)、新しいポイントを作成するためにマージされている必要があるとき、それを注意するか、あるいは以前にかなり良いendposのコレクションを破壊します。
少し注意
- 我々は試合の長さ、もし現在のポイントを計算するとき\([L、R] \ ) LENに彼の小さなリンク以外の右端endposの距離Lを、我々はリンクにジャンプしなければなりません。これは、適切な場所でより多くの新しいendposのを、獲得しているよう。
クロスLuogu後lojACの砂の彫刻、REを見つけます。最後に、これは関数の戻り値であることが証明されていないはず、著者はint型を書きますが、同時に、あまりにも直立羅与えていない谷で、その結果、ノーリターンはありません。コード
#include<bits/stdc++.h>
#define LL long long
#define MAXN 500000
using namespace std;
template<typename T>void Read(T &cn)
{
char c;int sig = 1;
while(!isdigit(c = getchar()))if(c == '-')sig = -1; cn = c-48;
while(isdigit(c = getchar()))cn = cn*10+c-48; cn*=sig;
}
template<typename T>void Write(T cn)
{
if(cn<0) {putchar('-'); cn = 0-cn; }
int wei = 0; T cm = 0; int cx = cn%10; cn/=10;
while(cn)wei++,cm = cm*10+cn%10,cn/=10;
while(wei--)putchar(cm%10+48),cm/=10;
putchar(cx+48);
}
int he[MAXN+1],xu[MAXN*2+1];
struct Seg{
struct node{
int ls,rs,da;
void qing() {ls = rs = da = 0; }
};
node t[MAXN*60+1];
int tlen;
int ro[MAXN*2+1];
void build() {tlen = 0; t[0].qing(); }
void jia(int &cn,int cm,int l,int r)
{
if(!cn)t[cn = ++tlen].qing();
if(l == r) {t[cn].da = cm; return; }
int zh = (l+r)>>1;
if(cm <= zh)jia(t[cn].ls,cm,l,zh); else jia(t[cn].rs,cm,zh+1,r);
t[cn].da = max(t[t[cn].ls].da,t[t[cn].rs].da);
}
int cha(int cn,int cm,int l,int r)
{
if(!cn)return 0;
if(r <= cm)return t[cn].da;
int zh = (l+r)>>1;
if(cm > zh)return max(cha(t[cn].rs,cm,zh+1,r),t[t[cn].ls].da);
else return cha(t[cn].ls,cm,l,zh);
}
void bing(int &cn,int cm1,int cm2,int l,int r)
{
if(!cm1 && !cm2)return;
if(!cm1) {cn = cm2; return; }
if(!cm2) {cn = cm1; return; }
cn = ++tlen;
t[cn].da = max(t[cm1].da,t[cm2].da);
if(l == r)return;
bing(t[cn].ls,t[cm1].ls,t[cm2].ls,l,(l+r)>>1);
bing(t[cn].rs,t[cm1].rs,t[cm2].rs,((l+r)>>1)+1,r);
}
}T;
struct SAM{
struct node{
int link,len,ch[26];
int edp,f;
void qing() {link = len = 0; memset(ch,0,sizeof(ch)); }
};
node t[MAXN*2+1];
int tlen,last;
void build() {t[tlen = last = 1].qing(); }
void jia(int cn,int cm)
{
int cur = ++tlen;
t[cur].qing();
t[cur].edp = cm;
t[cur].len = t[last].len+1;
int p = last;
for(;p && !t[p].ch[cn];p = t[p].link)t[p].ch[cn] = cur;
if(!p)t[cur].link = 1;
else{
int q = t[p].ch[cn];
if(t[p].len +1 == t[q].len)t[cur].link = q;
else{
int cln = ++tlen;
t[cln] = t[q]; t[cln].edp = 0;
t[cln].len = t[p].len+1;
t[cur].link = t[q].link = cln;
for(;p && t[p].ch[cn] == q;p = t[p].link)t[p].ch[cn] = cln;
}
}
last = cur;
}
void pro_edp()
{
T.build();
for(int i = 0;i<=t[last].len;i++)he[i] = 0;
for(int i = 1;i<=tlen;i++)he[t[i].len]++;
for(int i = 1;i<=t[last].len;i++)he[i] += he[i-1];
for(int i = 1;i<=tlen;i++)xu[he[t[i].len]--] = i;
for(int i = tlen;i>=1;i--)
{
if(t[xu[i]].edp)T.jia(T.ro[xu[i]],t[xu[i]].edp,1,t[last].len);
if(t[xu[i]].link)T.bing(T.ro[t[xu[i]].link],T.ro[t[xu[i]].link],T.ro[xu[i]],1,t[last].len);
}
}
int tongji(int n,int l,int r,int ans[],char c[])
{
int dang = 1,xian = 0;
for(int i = 1;i<=n;i++)
{
int lin = t[dang].ch[c[i]-'a'],lin2;
while(dang != 1 && (!lin || T.cha(T.ro[lin],r,1,t[last].len) < l))dang = t[dang].link,lin = t[dang].ch[c[i]-'a'],xian = min(xian,t[dang].len);
if(lin && T.cha(T.ro[lin],r,1,t[last].len) >= l)dang = lin,xian++; lin2 = T.cha(T.ro[dang],r,1,t[last].len);
while(dang != 1 && t[t[dang].link].len >= lin2 - l+1)dang = t[dang].link,xian = t[dang].len,lin2 = T.cha(T.ro[dang],r,1,t[last].len);
ans[i] = min(xian,lin2-l+1);
}
}
LL jisuan(int a[])
{
for(int i = 0;i<=t[last].len;i++)he[i] = 0;
for(int i = 1;i<=tlen;i++)he[t[i].len]++,t[i].f = 0;
for(int i = 1;i<=t[last].len;i++)he[i] += he[i-1];
for(int i = 1;i<=tlen;i++)xu[he[t[i].len]--] = i;
LL guo = 0;
for(int i = tlen;i>=1;i--)
{
if(t[xu[i]].edp)t[xu[i]].f = max(a[t[xu[i]].edp],t[xu[i]].f);
t[xu[i]].f = min(t[xu[i]].f,t[xu[i]].len);
guo = guo + t[xu[i]].len - max(t[xu[i]].f,t[t[xu[i]].link].len);
t[t[xu[i]].link].f = max(t[t[xu[i]].link].f,t[xu[i]].f);
}
return guo;
}
}S1,S2;
int clen,dlen;
char c[MAXN*2+1],d[MAXN*2+1];
int a[MAXN*2+1];
int n;
void getit(char c[],int &n)
{
while(!isalpha(c[1] = getchar())); n = 1;
while(isalpha(c[++n] = getchar())); n--;
}
int main()
{
// freopen("name1.in","r",stdin);
// freopen("name1.out","w",stdout);
getit(c,clen); S1.build();
for(int i = 1;i<=clen;i++)S1.jia(c[i]-'a',i); S1.pro_edp();
Read(n);
while(n--)
{
getit(d,dlen); int bx,by; Read(bx); Read(by);
S1.tongji(dlen,bx,by,a,d);
S2.build(); for(int i = 1;i<=dlen;i++)S2.jia(d[i]-'a',i);
Write(S2.jisuan(a)); putchar('\n');
}
return 0;
}