Description
你有個串,有兩種操作
- 給的串在前面拼上新串。
- 詢問
Solution
考慮把所有添加串+初始串拼成一個大串。那麼所有串顯然是這個大串的若干個不相交的子串拼起來的。
考慮用線段樹維護每個串。如果某個串是由拼成的,那麼在它的線段樹對區間執行操作。由於每次操作是對一段區間的串添加上一個子串,所以考慮用線段樹套線段樹維護所有的串。如果對一段區間的串拼上一個串,那麼在第一維線段樹上的區間打上標記,這個標記是一棵在上的第二維線段樹。下傳標記就是線段樹合併。由於範圍不交,所以複雜度是(是的長度)。
考慮詢問,由於。所以維護相鄰兩個串的即可。考慮修改對的影響,顯然只會影響和,對於加上添加串的長度即可。
#include <bits/stdc++.h>
using namespace std;
inline int gi()
{
char c = getchar();
while(c < '0' || c > '9') c = getchar();
int sum = 0;
while('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
typedef unsigned int uint;
const int maxn = 50005, maxs = 600005;
int n, m;
int S[maxs], cnt, st[maxn], en[maxn], stq[maxn], enq[maxn];
int q[maxn][3];
char s[maxs];
uint Pow[maxs];
int rt[maxn]; //每個串在sgt1上的根
#define mid ((l + r) >> 1)
namespace sgt1
{
const int maxn = maxs * 60;
int tot, lch[maxn], rch[maxn], sum[maxn];
uint h[maxn];
void update(int s)
{
sum[s] = sum[lch[s]] + sum[rch[s]];
h[s] = h[lch[s]] * Pow[sum[rch[s]]] + h[rch[s]];
}
void build(int &s, int l, int r, int ql, int qr)
{
s = ++tot;
if (l == r) return sum[s] = 1, h[s] = S[l], void();
if (ql <= mid) build(lch[s], l, mid, ql, qr);
if (qr >= mid + 1) build(rch[s], mid + 1, r, ql, qr);
update(s);
}
int merge(int s1, int s2)
{
if (!s1 || !s2) return s1 | s2;
int s = ++tot;
lch[s] = merge(lch[s1], lch[s2]);
rch[s] = merge(rch[s1], rch[s2]);
return update(s), s;
}
uint hash(int s, int l, int r, int k)
{
if (l == r) return k ? h[s] : 0;
if (sum[lch[s]] >= k) return hash(lch[s], l, mid, k);
else return k -= sum[lch[s]], h[lch[s]] * Pow[k] + hash(rch[s], mid + 1, r, k);
}
}
#define lch (s << 1)
#define rch (s << 1 | 1)
namespace sgt2
{
int tag[maxs << 2];
inline void pushdown(int s)
{
if (!tag[s]) return ;
tag[lch] = sgt1::merge(tag[lch], tag[s]);
tag[rch] = sgt1::merge(tag[rch], tag[s]);
tag[s] = 0;
}
void modify(int s, int l, int r, int ql, int qr, int x)
{
if (ql <= l && r <= qr) return tag[s] = sgt1::merge(tag[s], x), void();
pushdown(s);
if (ql <= mid) modify(lch, l, mid, ql, qr, x);
if (qr >= mid + 1) modify(rch, mid + 1, r, ql, qr, x);
}
void query(int s, int l, int r, int p)
{
if (l == r) return rt[p] = sgt1::merge(rt[p], tag[s]), tag[s] = 0, void();
pushdown(s);
if (p <= mid) query(lch, l, mid, p);
else query(rch, mid + 1, r, p);
}
int lcp(int x, int y)
{
query(1, 1, n, x); query(1, 1, n, y);
x = rt[x]; y = rt[y];
int l = 0, r = min(sgt1::sum[x], sgt1::sum[y]), Mid;
while (l < r) {
Mid = (l + r + 1) >> 1;
if (sgt1::hash(x, 1, cnt, Mid) != sgt1::hash(y, 1, cnt, Mid)) r = Mid - 1;
else l = Mid;
}
return l;
}
}
namespace sgt3
{
int h[maxn << 2], tag[maxn << 2];
inline void pushdown(int s)
{
if (!tag[s]) return ;
h[lch] += tag[s]; tag[lch] += tag[s];
h[rch] += tag[s]; tag[rch] += tag[s];
tag[s] = 0;
}
inline void update(int s) {h[s] = min(h[lch], h[rch]);}
void build(int s, int l, int r)
{
if (l == r) return h[s] = sgt2::lcp(l, l + 1), void();
build(lch, l, mid);
build(rch, mid + 1, r);
update(s);
}
void modify(int s, int l, int r, int p)
{
if (l == r) return h[s] = sgt2::lcp(l, l + 1), void();
pushdown(s);
if (p <= mid) modify(lch, l, mid, p);
else modify(rch, mid + 1, r, p);
update(s);
}
void modify(int s, int l, int r, int ql, int qr, int v)
{
if (ql <= l && r <= qr) return h[s] += v, tag[s] += v, void();
pushdown(s);
if (ql <= mid) modify(lch, l, mid, ql, qr, v);
if (qr >= mid + 1) modify(rch, mid + 1, r, ql, qr, v);
update(s);
}
int query(int s, int l, int r, int ql, int qr)
{
if (ql <= l && r <= qr) return h[s];
pushdown(s);
int res = 1e9;
if (ql <= mid) res = query(lch, l, mid, ql, qr);
if (qr >= mid + 1) res = min(res, query(rch, mid + 1, r, ql, qr));
return res;
}
}
int main()
{
freopen("uzi.in", "r", stdin);
freopen("uzi.out", "w", stdout);
n = gi(); m = gi();
static int tmp[maxs];
for (int len, i = 1; i <= n; ++i) {
scanf("%s", s + 1); len = strlen(s + 1);
st[i] = cnt + 1;
for (int j = 1; j <= len; ++j) tmp[++cnt] = s[j] - 'a';
en[i] = cnt;
}
char c;
for (int len, i = 1; i <= m; ++i) {
c = getchar();
while (c < 'A' || c > 'Z') c = getchar();
q[i][1] = gi(); q[i][2] = gi();
if (c == 'Q') q[i][0] = 1;
else {
scanf("%s", s + 1); len = strlen(s + 1);
stq[i] = cnt + 1;
for (int j = 1; j <= len; ++j) tmp[++cnt] = s[j] - 'a';
enq[i] = cnt;
}
}
cnt = 0;
for (int i = m, l, r; i >= 1; --i)
if (!q[i][0]) {
l = stq[i]; r = enq[i];
stq[i] = cnt + 1;
for (int j = l; j <= r; ++j) S[++cnt] = tmp[j];
enq[i] = cnt;
}
for (int i = 1, l, r; i <= n; ++i) {
l = st[i]; r = en[i];
st[i] = cnt + 1;
for (int j = l; j <= r; ++j) S[++cnt] = tmp[j];
en[i] = cnt;
}
Pow[0] = 1;
for (int i = 1; i <= cnt; ++i) Pow[i] = Pow[i - 1] * 141937;
for (int i = 1; i <= n; ++i) sgt1::build(rt[i], 1, cnt, st[i], en[i]);
if (n > 1) sgt3::build(1, 1, n - 1);
for (int l, r, i = 1; l = q[i][1], r = q[i][2], i <= m; ++i)
if (q[i][0]) {
if (l == r) sgt2::query(1, 1, n, l), printf("%d\n", sgt1::sum[rt[l]]);
else printf("%d\n", sgt3::query(1, 1, n - 1, l, r - 1));
} else {
int tag;
sgt1::build(tag, 1, cnt, stq[i], enq[i]);
sgt2::modify(1, 1, n, l, r, tag);
if (l < r) sgt3::modify(1, 1, n - 1, l, r - 1, enq[i] - stq[i] + 1);
if (l > 1) sgt3::modify(1, 1, n - 1, l - 1);
if (r < n) sgt3::modify(1, 1, n - 1, r);
}
return 0;
}