版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82459587
【题目链接】
【思路要点】
- 记 表示 和 的 的长度,对一段区间 增加一个前缀,那么 都会对应增加这个前缀的长度, 和 需要重新计算。
- 用线段树套可持久化 维护 ,在 中维护部分的哈希值,重新计算时先二分长度,比较哈希值即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 5e4 + 5;
const int MAXS = 6e5 + 5;
const int MAXP = 8e6 + 5;
const int INF = 1e9;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct Treap {
struct Node {
int lc, rc;
unsigned index;
int size, l, r; ull Hash;
} a[MAXP];
unsigned seed;
int size, len, sum;
char s[MAXS]; ull bit[MAXS], Hash[MAXS];
unsigned Rand() {
seed = seed * seed + rand();
return seed;
}
void init() {
sum = 0;
size = 0;
seed = 1;
bit[0] = 1;
for (int i = 1; i < MAXS; i++)
bit[i] = bit[i - 1] * 27;
}
ull gethash(int l, int r) {
int len = r - l + 1;
return Hash[r] - Hash[l - 1] * bit[len];
}
void update(int x) {
a[x].size = a[x].r - a[x].l + 1;
a[x].Hash = gethash(a[x].l, a[x].r);
if (a[x].lc) {
int tmp = a[x].lc;
a[x].size += a[tmp].size;
a[x].Hash += a[tmp].Hash * bit[a[x].r - a[x].l + 1];
}
if (a[x].rc) {
int tmp = a[x].rc;
a[x].size += a[tmp].size;
a[x].Hash *= bit[a[tmp].size];
a[x].Hash += a[tmp].Hash;
}
}
int merge(int x, int y) {
if (x == 0 || y == 0) return x + y;
if (a[x].index < a[y].index) {
int ans = ++size;
a[ans] = a[x];
a[ans].rc = merge(a[ans].rc, y);
update(ans);
return ans;
} else {
int ans = ++size;
a[ans] = a[y];
a[ans].lc = merge(x, a[ans].lc);
update(ans);
return ans;
}
}
int load() {
scanf("\n%s", s + sum + 1);
len = strlen(s + sum + 1);
int ans = ++size;
a[ans].size = len;
a[ans].l = sum + 1;
a[ans].r = sum + len;
a[ans].index = Rand();
for (int i = sum + 1; i <= sum + len; i++)
Hash[i] = Hash[i - 1] * 27 + s[i] - 'a' + 1;
a[ans].Hash = gethash(sum + 1, sum + len);
sum += len;
return ans;
}
int length(int root) {
return a[root].size;
}
ull calc(int root, int lft) {
if (a[root].size == lft) return a[root].Hash;
if (a[a[root].lc].size >= lft) return calc(a[root].lc, lft);
ull ans = a[a[root].lc].Hash;
lft -= a[a[root].lc].size;
int len = a[root].r - a[root].l + 1;
if (lft <= len) return ans * bit[lft] + gethash(a[root].l, a[root].l + lft - 1);
else return ans * bit[lft] + gethash(a[root].l, a[root].r) * bit[lft - len] + calc(a[root].rc, lft - len);
}
int lcp(int x, int y) {
int l = 0, r = min(a[x].size, a[y].size);
while (l < r) {
int mid = (l + r + 1) / 2;
if (calc(x, mid) == calc(y, mid)) l = mid;
else r = mid - 1;
}
return l;
}
} Treap;
struct SegmentTree {
struct Node {
int lc, rc;
int root, add, Min;
} a[MAXN * 2];
int root, size, n, last;
void update(int root) {
a[root].Min = min(a[a[root].lc].Min, a[a[root].rc].Min);
}
void build(int &root, int l, int r) {
root = ++size;
a[root].add = 0;
a[root].Min = 0;
if (l == r) {
a[root].root = Treap.load();
if (last != 0) a[root].Min = Treap.lcp(a[root].root, a[last].root);
last = root;
return;
}
int mid = (l + r) / 2;
build(a[root].lc, l, mid);
build(a[root].rc, mid + 1, r);
update(root);
}
void pushdown(int root, bool type) {
if (a[root].lc) {
int tmp = a[root].lc;
a[tmp].Min += a[root].add, a[tmp].add += a[root].add;
if (type) a[tmp].root = Treap.merge(a[root].root, a[tmp].root);
}
if (a[root].rc) {
int tmp = a[root].rc;
a[tmp].Min += a[root].add, a[tmp].add += a[root].add;
if (type) a[tmp].root = Treap.merge(a[root].root, a[tmp].root);
}
a[root].add = 0; if (type) a[root].root = 0;
}
void init(int x) {
root = size = 0;
last = 0; n = x;
build(root, 1, n);
}
void access(int root, int l, int r, int pos) {
if (l == r) {
last = root;
return;
}
pushdown(root, true);
int mid = (l + r) / 2;
if (mid >= pos) access(a[root].lc, l, mid, pos);
else access(a[root].rc, mid + 1, r, pos);
}
int query(int root, int l, int r, int ql, int qr) {
if (l == ql && r == qr) return a[root].Min;
int mid = (l + r) / 2;
pushdown(root, false);
if (mid >= qr) return query(a[root].lc, l, mid, ql, qr);
else if (mid + 1 <= ql) return query(a[root].rc, mid + 1, r, ql, qr);
else return min(query(a[root].lc, l, mid, ql, mid), query(a[root].rc, mid + 1, r, mid + 1, qr));
}
int query(int l, int r) {
access(root, 1, n, l);
int ans = Treap.length(a[last].root);
if (l != r) chkmin(ans, query(root, 1, n, l + 1, r));
return ans;
}
void modify(int root, int l, int r, int ql, int qr, int rt) {
if (l == ql && r == qr) {
a[root].root = Treap.merge(rt, a[root].root);
return;
}
pushdown(root, true);
int mid = (l + r) / 2;
if (mid >= qr) modify(a[root].lc, l, mid, ql, qr, rt);
else if (mid + 1 <= ql) modify(a[root].rc, mid + 1, r, ql, qr, rt);
else modify(a[root].lc, l, mid, ql, mid, rt), modify(a[root].rc, mid + 1, r, mid + 1, qr, rt);
}
void add(int root, int l, int r, int ql, int qr, int len) {
if (l == ql && r == qr) {
a[root].Min += len;
a[root].add += len;
return;
}
pushdown(root, false);
int mid = (l + r) / 2;
if (mid >= qr) add(a[root].lc, l, mid, ql, qr, len);
else if (mid + 1 <= ql) add(a[root].rc, mid + 1, r, ql, qr, len);
else add(a[root].lc, l, mid, ql, mid, len), add(a[root].rc, mid + 1, r, mid + 1, qr, len);
}
void recalc(int root, int l, int r, int pos) {
if (l == r) {
a[root].Min = Treap.lcp(a[root].root, a[last].root);
return;
}
pushdown(root, true);
int mid = (l + r) / 2;
if (mid >= pos) recalc(a[root].lc, l, mid, pos);
else recalc(a[root].rc, mid + 1, r, pos);
update(root);
}
void recalc(int pos) {
access(root, 1, n, pos - 1);
recalc(root, 1, n, pos);
}
void modify(int l, int r, int rt) {
modify(root, 1, n, l, r, rt);
if (l != r) add(root, 1, n, l + 1, r, Treap.length(rt));
if (l != 1) recalc(l);
if (r != n) recalc(r + 1);
}
} ST;
char getopt() {
char ch = getchar();
while (ch != 'I' && ch != 'Q') ch = getchar();
return ch;
}
int main() {
int n, m; read(n), read(m);
Treap.init(), ST.init(n);
for (int i = 1; i <= m; i++) {
if (getopt() == 'Q') {
int l, r; read(l), read(r);
writeln(ST.query(l, r));
} else {
int l, r; read(l), read(r);
int tmp = Treap.load();
ST.modify(l, r, tmp);
}
}
return 0;
}