【HNOI2019] JOJO

【HNOI2019] JOJO

[トピックのリンク]

リンク

[思考ポイント]

対象が現在の文字列実行するように要求される\(\テキスト{KMPを} \ ) の後に(\ \テキスト{NXT} \ ) アレイの値と

ケースない第2の動作最初検討

追加操作を文字として追加され、文字は二つの属性、長さや性格を持っています。

タイトルは、接頭辞と接尾辞に一致する必要がありながら、両者が一致するサブストリングは、各ストリングは、接頭語+接尾辞+中間セグメントの完全なスタックの先頭の一定期間の終わりの部分に分割されて見つけることが困難で、それは文字列セクションの始まりが完了している、文字列の最後には、文字列の最後のセグメントの始まりは、最初の文字列よりも長くなる場合があり、完全なエンド・セグメント、および最終的には最初の文字列より文字列かもしれないの最後のセクションであります短いです

中間部分正確に一致するので、それが行われ、直接共通\(\テキスト{KMPは} \ ) 先頭に何ら変更がないため、直接すべての文字の最初の完全な一致をレンダリングすることができ、それは同じ長さであるが、そのセグメント以上うまく処理、キーは、文字列の末尾に対処することです

考えてみましょう\(\テキスト{KMP} \ ) 実装プロセス、本質的には、常にジャンプしている\(NXT \)タイトルが文字にそれぞれの添加を保証していないため、プロセスを同じ、の最後の文字の前に\(NXT \)ジャンプ一致が不可能中間期間である場合、それはいくつかの場合には減少させることができます。文字の最後の段落を設定したい場合がありますc今ジャンプ\(NXT \) 3つの文字が続いているがありますがc、最初の時など(p1,c,l1)のために、第二位(p2,c,l2)である第三位(p3,c,l3)p表し\(NXT \)の値を、つまり、位置にジャンプし、lこの期間語っc長さは。仮定p1<p2<p3l1>l2>l3

新たに追加された現在の設定明確次に、c長さl、下付き文字は[1,l]、その後[1,l3]の期間は、第三に一致すべきである[l3+1,l2]期間を第二試合で、すなわち各期間見つけるためにcいくつかの位置のために覆われ、および上カバーの前面を覆っていません位置(良好でない)、各寄与は、演算シーケンスの一部です。

そのような複雑さは、\(\シータ(M)\ ) 。第2の動作を追加することを検討してください。まず、ツリーの操作が構築することができ、dfs操作を元に戻すが、以降に完了\(\ \テキスト{KMP} )複雑さが償却される(\ \シータ(1)\ ) 、及び各動作は非常に迅速に保証することができないので、停止以前の状態に戻り、低速のカードは、アルゴリズムの外に動作することができるようになりますか。本質的に、およその範囲内の文字の総数ので\(1E9の\)ほど、暴力は、kmpパスの端にあった、剪定鋏を通過することができるかもしれません。

呼ばれる考えてみましょう(\ \テキスト{KMP} \を ) もの自動機を、その本質は、することです(\テキスト{KMP} \ \ ) ホップ\(\テキスト{NXT} \ ) タイトル文字セットとして、前処理工程のを木のメンテナンスの社長と大きなサイズ、。

セット\(F_ {I、J、 Kは} \) の文字列を表す(S_ {I-1} \ )\ 文字位置追加\((J、K)を\ ) の後に\(NXT \)に達した位置、同様に設定\(G_ {I、J、 K} \) 回答の増加を表します。dfs時間、変更\(F_ {I、X、 C} \) の値、および(G_ {I、X、1つの \ \点Cを} \) 項目設定公差、現在の文字列の長さにつながっ\(1 \)等差数列の。dfs次の層の前に\(F_ {I + 1} \) によって状態\(F_ {次の[i]は +1} \) 継承されました。各添加は等差数列であるので、そのゾーンの割り当てになるように、それぞれ低い値根底にある統計に結合され、プリマイナスインデックス値とすることができます。

[コード]

// Copyright: lzt
#include<stdio.h>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<map>
#include<set>
#include<cmath>
#include<iostream>
#include<queue>
#include<string>
#include<ctime>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<long long,long long> pll;
typedef pair<int, pair<int, long long> > lzt;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define rep(i,j,k)  for(register int i=(int)(j);i<=(int)(k);i++)
#define rrep(i,j,k) for(register int i=(int)(j);i>=(int)(k);i--)
#define Debug(...) fprintf(stderr, __VA_ARGS__)

ll read(){
    ll x=0,f=1;char c=getchar();
    while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0' && c<='9'){x=x*10+c-'0';c=getchar();}
    return x*f;
}

inline char gc() {
    char c = getchar();
    while (c < 'a' || c > 'z') c = getchar();
    return c;
}

const int maxn = 100005, M = 1e4 + 7, mod = 998244353;

int n;
int val[maxn], pos[maxn], ans[maxn], a[maxn], b[maxn], top;
vector<int> to[maxn];

int rt[maxn][26], mx[maxn][26], tot;
struct seg
{
    int l, r, lch, rch, sum, lzy, nxt;
} t[maxn * 60];

#define mid ((l + r) >> 1)

inline void new_node(int &s) {t[++tot] = t[s]; s = tot;}
inline void add(int s, int v, int len) {t[s].sum = (ll)v * len % mod; t[s].lzy = v;}
inline void push_down(int s, int l, int r)
{
    if (!t[s].lzy) return ;
    new_node(t[s].lch); add(t[s].lch, t[s].lzy, mid - l + 1);
    new_node(t[s].rch); add(t[s].rch, t[s].lzy, r - mid);
    t[s].lzy = 0;
}

void modify(int &s, int l, int r, int x, int v, int p)
{
    new_node(s);
    if (r < x) return add(s, v, r - l + 1);
    if (l == r) return t[s].nxt = p, add(s, v, 1);
    push_down(s, l, r);
    modify(t[s].lch, l, mid, x, v, p);
    if (x > mid) modify(t[s].rch, mid + 1, r, x, v, p);
    t[s].sum = (t[t[s].lch].sum + t[t[s].rch].sum) % mod;
}

void query(int &s, int l, int r, int x, int &ans, int &nxt)
{
    if (r < x) return ans = (ans + t[s].sum) % mod, void();
    if (l == r) return ans = (ans + t[s].sum) % mod, nxt = t[s].nxt, void();
    push_down(s, l, r);
    query(t[s].lch, l, mid, x, ans, nxt);
    if (x > mid) query(t[s].rch, mid + 1, r, x, ans, nxt);
}

inline int getsum(int x) {return ((ll)x * (x + 1) >> 1) % mod;}

void dfs(int u)
{
    ++top;
    int x = val[u] / M, y = val[u] % M, nxt = 0;
    a[top] = val[u]; b[top] = b[top - 1] + y;
    if (top == 1) ans[u] = getsum(y - 1);
    else {
        ans[u] = (ans[u] + getsum(min(mx[top][x], y))) % mod;
        query(rt[top][x], 1, M, y, ans[u], nxt);
        if (!nxt && a[1] / M == x && b[1] < y) nxt = 1, ans[u] = (ans[u] + (ll)b[1] * max(0, y - mx[top][x])) % mod;
    }
    mx[top][x] = max(mx[top][x], y);
    modify(rt[top][x], 1, M, y, b[top - 1], top);
    for (int i=0;i<to[u].size();i++) {
        int v = to[u][i];
        memcpy(mx[top + 1], mx[nxt + 1], sizeof(mx[top + 1]));
        memcpy(rt[top + 1], rt[nxt + 1], sizeof(rt[top + 1]));
        ans[v] = ans[u]; dfs(v);
    }
    --top;
}

void work() {
    n = read();
    for (int op, x, i = 1; i <= n; ++i) {
        op = read(); x = read();
        if (op == 1) val[++tot] = (gc() - 'a') * M + x, pos[i] = tot, to[pos[i - 1]].push_back(pos[i]);
        else pos[i] = pos[x];
    }

    for (int _ = 0; _ < to[0].size(); _++) {
        int i = to[0][_];
        tot = 0;
        memset(rt[1], 0, sizeof(rt[1]));
        memset(mx[1], 0, sizeof(mx[1]));
        dfs(i);
    }

    for (int i = 1; i <= n; ++i) printf("%d\n", ans[pos[i]]);
}

int main(){
    #ifdef LZT
        freopen("in","r",stdin);
    #endif

    work();

    #ifdef LZT
        Debug("My Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
    #endif
}

おすすめ

転載: www.cnblogs.com/wawawa8/p/11108612.html