ディレクトリ
@説明@
ION年には文字列名を設定し、それぞれの質問の要件の名前は、文字列の名前の行に空でない部分文字列の年でなければならず、いずれかのトピックは、前年と同じ名前することはできません。
いくつかの特別な理由なので、ION2017の小さな文字列と命名されました。
小さなQ時間が今求めている:それぞれがION2017 ION2018名の文字列と文字列名を与えられた、いくつかの要件サブジェクト名があり、名前は連続非ヌルサブION2018は、文字列と文字列の名前とないようなものですいずれかのトピックION2017名と同じ。
いくつかの特別な理由なので、ION2017のお問い合わせ与えられたすべての名前は、文字列の部分文字列の連続文字列です。
入力形式
name.inは、ファイルからデータを読み込みます。
お問い合わせにちなんで名付けられた文字列Sの最初の行は、S.ストリングのION2017連続文字列を与えられています
2行目は、正の整数Qは、質問の数を表します。
次Q線、2つの正の整数とT Lの列を有し、各ラインは、R、クエリ文字列名を表しION2017場合S [L、R]、ION2018名文字列は、その後、いくつかの方法がTありされている特定のネーミング要件を満たしています。
入力文字列が小文字の構成によって与えられることを確認してください。
出力フォーマット
のファイルname.outに出力。
Q出力線、i番目の行はiは番目の問い合わせに答える非負の整数を表します。
サンプル入力1
scbamgepe
。3
smape 2. 7
sbape。3. 8
sgepe。9. 1
出力1試料
12は
10
。4
データの範囲やヒント
保証すべてのデータ、1 <= L <= R&LT <= |。| S <= 5 。10 ^ 5 ,. 1 <= | T | <= 5。 10 ^ 5、[シグマ|。T | <= 10 ^ 6 、Q <= 10 ^ 5。
@溶液@
S | |ケースL = 1、R =考えてみましょう。
私たちは、その後、T、Sの実行を得るために走った、Sサフィックスオートマトンを構築したいです Tの各プレフィックスiについて、我々は[i]は、プレフィックスの長さT iがFであるように、fは最大値を得る[i]はSの部分文字列の接尾辞です。
明らかに、私は<プレフィックスの長さ= Fすべてのサフィックスは、[I]はまたS.で登場します
我々は、次いで[i]は各タグのプレフィックスノードに対応するfのマークされたTサフィックスオートマトンを構築し、次に親タグツリーに沿って通過します。
この方法は、Sに表示されていない各ノード番号に対応するTサフィックスオートマトン文字列を処理することができます だから我々は、お問い合わせの問題を解決することができます。
我々は、[i]はfの各iについてと判定考えるときに指定した文字列がサブストリングS [L ... R]はS考えます。
私たちは、各ノードがエンド-POSのサフィックスオートマトンの集合Sを取得し、組み合わせた持続セグメントツリーの使用を考慮することができます。
マッチングは、S [L ... R]にできるだけ成功した場合、プレフィックスノードのT iは、サフィックスオートマトンS xを一致したとき、我々は、エンドPOSを選択するように設定されなければならない<= R、できるだけ大きく且つその。バイナリツリーライン]をクリックします。
このような末端-POSまたは左のポイントを超えて終了-POS対応する文字列があればマッチが失敗したとして、私たちは、親木に沿ってジャンプし続けます。
だから、ダウン、それをツリーラインを要するので、時間の複雑さはOである(| T | * LOGN)です。
@acceptedコード@
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 1000000;
struct segtree{
struct node{
int ch[2], mx;
}pl[20*MAXN + 5];
int ncnt;
segtree() {ncnt = 0; pl[0].mx = -1;}
void pushup(int x) {
if( pl[x].ch[1] ) pl[x].mx = pl[pl[x].ch[1]].mx;
else pl[x].mx = pl[pl[x].ch[0]].mx;
}
int merge(int a, int b) {
if( !a ) return b;
if( !b ) return a;
int c = (++ncnt);
pl[c].ch[0] = merge(pl[a].ch[0], pl[b].ch[0]);
pl[c].ch[1] = merge(pl[a].ch[1], pl[b].ch[1]);
pushup(c);
return c;
}
int insert(int a, int l, int r, int p) {
int b = (++ncnt); pl[b].ch[0] = pl[a].ch[0], pl[b].ch[1] = pl[a].ch[1];
if( l == r ) {
pl[b].mx = l;
return b;
}
int mid = (l + r) >> 1;
if( p <= mid ) pl[b].ch[0] = insert(pl[a].ch[0], l, mid, p);
else pl[b].ch[1] = insert(pl[a].ch[1], mid + 1, r, p);
pushup(b);
return b;
}
int query(int x, int l, int r, int p) {
if( l == r ) return pl[x].mx;
int mid = (l + r) >> 1;
if( p <= mid ) return query(pl[x].ch[0], l, mid, p);
else {
int k = query(pl[x].ch[1], mid + 1, r, p);
if( k != -1 ) return k;
else return pl[pl[x].ch[0]].mx;
}
}
};
struct SAM{
struct node{
node *ch[26], *fa;
int mx, pos, tag;
}pl[2*MAXN + 5], *lst, *root, *ncnt;
SAM() {ncnt = lst = root = &pl[0];}
void clear() {
int size = ncnt - pl + 1;
for(int i=0;i<size;i++) {
for(int j=0;j<26;j++)
pl[i].ch[j] = NULL;
pl[i].fa = NULL, pl[i].mx = pl[i].pos = pl[i].tag = 0;
}
ncnt = lst = root = &pl[0];
}
void extend(int c) {
node *cur = (++ncnt), *p = lst; lst = cur;
cur->mx = cur->pos = p->mx + 1;
while( p && p->ch[c] == NULL )
p->ch[c] = cur, p = p->fa;
if( !p )
cur->fa = root;
else {
node *q = p->ch[c];
if( p->mx + 1 == q->mx )
cur->fa = q;
else {
node *cne = (++ncnt); (*cne) = (*q);
cne->mx = p->mx + 1; cne->pos = 0;
cur->fa = q->fa = cne;
while( p && p->ch[c] == q )
p->ch[c] = cne, p = p->fa;
}
}
}
node *a[2*MAXN + 5]; int b[2*MAXN + 5];
segtree T; int rt[2*MAXN + 5];
void sort(int len) {
int size = ncnt - pl + 1;
for(int i=1;i<=len;i++) b[i] = 0;
for(int i=0;i<size;i++) b[pl[i].mx]++;
for(int i=1;i<=len;i++) b[i] += b[i-1];
for(int i=0;i<size;i++) a[--b[pl[i].mx]] = &pl[i];
}
void build(int len) {
int size = ncnt - pl + 1; sort(len);
for(int i=0;i<size;i++)
rt[i] = 0;
for(int i=size-1;i>0;i--) {
if( a[i]->pos )
rt[a[i]-pl] = T.insert(rt[a[i]-pl], 1, len, a[i]->pos);
rt[a[i]->fa-pl] = T.merge(rt[a[i]->fa-pl], rt[a[i]-pl]);
}
}
long long solve(int len) {
int size = ncnt - pl + 1; sort(len);
long long ret = 0;
for(int i=size-1;i>0;i--)
a[i]->fa->tag = min(a[i]->fa->mx, max(a[i]->fa->tag, a[i]->tag)), ret += max(0, a[i]->mx - max(a[i]->fa->mx, a[i]->tag));
return ret;
}
void debug(int len) {
int size = ncnt - pl + 1;
for(int i=0;i<size;i++) {
printf("%d : %d %d %d %d\n", i, pl[i].fa-pl, pl[i].mx, pl[i].pos, pl[i].tag);
//T.debug(rt[i], 1, len);
}
puts("");
}
}S, T;
char str[MAXN + 5];
int mx[MAXN + 5];
int main() {
freopen("name.in", "r", stdin);
freopen("name.out", "w", stdout);
scanf("%s", str);
int lenS = strlen(str);
for(int i=0;i<lenS;i++)
S.extend(str[i] - 'a');
S.build(lenS);
int Q; scanf("%d", &Q);
for(int i=1;i<=Q;i++) {
int l, r, lenT;
scanf("%s%d%d", str, &l, &r), lenT = strlen(str);
SAM::node *nw = S.root; int tmp = 0, x;
for(int j=0;j<lenT;j++) {
while( nw && nw->ch[str[j]-'a'] == NULL )
nw = nw->fa;
if( nw ) {
tmp = min(tmp, nw->mx) + 1, nw = nw->ch[str[j]-'a'];
x = S.T.query(S.rt[nw-S.pl], 1, lenS, r);
while( nw ) {
if( x == -1 ) nw = nw->fa;
else {
if( nw == S.root || l + nw->fa->mx <= x ) break;
else nw = nw->fa;
}
if( nw ) x = S.T.query(S.rt[nw-S.pl], 1, lenS, r);
}
if( nw )
tmp = min(tmp, min(x - l + 1, nw->mx));
else tmp = 0, nw = S.root;
}
else tmp = 0, nw = S.root;
mx[j] = tmp;
}
for(int j=0;j<lenT;j++)
T.extend(str[j]-'a');
nw = T.root;
for(int j=0;j<lenT;j++) {
nw = nw->ch[str[j]-'a'];
nw->tag = mx[j];
}
printf("%lld\n", T.solve(lenT));
T.clear();
}
}
@詳細@
私たちはすべての時間Tサフィックスオートマトンを空にするために注意を払うように求めた後、複数のTサフィックスオートマトンを構築したいので。