蜜汁卡常卡过去了。。。
考虑用线段树维护区间的LCP,如果设 height[i]=LCP(S[i],S[i+1]) ,那么 LCP(S[l]...S[r])=min(height[l]...height[r−1]) 。
只要能快速维护 height ,就可以快速查询。
于是考虑如何处理修改。
可以发现区间加前缀的时候, [l...r−1] 的 height 相当于直接加上了前缀的长度,而 height[l−1] 和 height[r] 变得不确定了,于是可以重新算这两个位置的 height 。前一半区间加的部分可以直接线段树搞搞,后一半需要知道这个串现在长什么样。
于是考虑如何算 height[i] 。我们可以用Treap维护每个字符串的哈希值,于是区间插入的时候相当于区间的Treap前面join再上一个Treap。因此可以将Treap可持久化之后直接当线段树上的标记来推。这样每次推标记的复杂度就是 O(logL) ,这部分修改的时间复杂度是 O(logLlogn) 。维护了哈希值就可以二分来算LCP了,所以一次修改的时间复杂度就是 O(logLlogn) 。
查询的复杂度为 O(logn) 。
总时间复杂度 O(mlogLlogn) 。
其实不是很难写嘛就是常数有点爆炸而已
/*
I will chase the meteor for you, a thousand times over.
Please wait for me, until I fade forever.
Just 'coz GEOTCBRL.
*/
#include
using std::min;
using std::pair;
using std::make_pair;
#define fore(i,u) for (int i = head[u] ; i ; i = nxt[i])
#define rep(i,a,b) for (int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for (int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for (int i = a , _ = b ; i < _ ; i ++)
#define Dwn(i,a,b) for (int i = ((int) a) - 1 , _ = (b) ; i >= _ ; i --)
#define fors(s0,s) for (int s0 = (s) , _S = s ; s0 ; s0 = (s0 - 1) & _S)
#define foreach(it,s) for (__typeof(s.begin()) it = s.begin(); it != s.end(); it ++)
#define mp make_pair
#define pb push_back
#define pii pair
#define fir first
#define sec second
#define MS(x,a) memset(x , (a) , sizeof (x))
#define gprintf(...) fprintf(stderr , __VA_ARGS__)
#define gout(x) std::cerr << #x << "=" << x << std::endl
#define gout1(a,i) std::cerr << #a << '[' << i << "]=" << a[i] << std::endl
#define gout2(a,i,j) std::cerr << #a << '[' << i << "][" << j << "]=" << a[i][j] << std::endl
#define garr(a,l,r,tp) rep (__it , l , r) gprintf(tp"%c" , a[__it] , " \n"[__it == _])
template inline void upmax(T&a , T b) { if (a < b) a = b ; }
template inline void upmin(T&a , T b) { if (a > b) a = b ; }
typedef long long ll;
const int maxn = 50007;
const int maxS = 600007;
const int maxs = 1 << 17;
const int maxm = 15000007;
const int mod = 1000000007;
const int inf = 0x7fffffff;
typedef int arr[maxn];
typedef int adj[maxm];
#define gc getchar
#define idg isdigit
#define rd RD
#define rdll RD
template
inline Type RD() {
char c = getchar(); Type x = 0 , flag = 1;
while (!idg(c) && c != '-') c = getchar();
if (c == '-') flag = -1; else x = c - '0';
while (idg(c = gc()))x = x * 10 + c - '0';
return x * flag;
}
inline char rdch() {
char c = gc();
while (!isalpha(c)) c = gc();
return c;
}
#undef idg
#undef gc
// beginning
#define uint unsigned int
uint pw1[maxS];
int n , m;
#define rnd rand
struct node {
uint l , r;
int sz , pri;
uint val1;
char c;
node() {}
node (char c): c(c) , sz(1) , pri(rnd()) {
if (c) val1 = c - 'a';
l = r = 0;
}
inline node operator+(node x) {
node tmp;
tmp.sz = sz + x.sz;
tmp.val1 = (val1 + pw1[sz] * x.val1);
return tmp;
}
};
node nd[maxm];
int tot;
#define u nd[x]
#define lsz nd[u.l].sz
#define rsz nd[u.r].sz
inline void upd(uint x) {
u.sz = 1 + lsz + rsz;
node tmp = node(u.c) + nd[u.r];
tmp = nd[u.l] + tmp;
u.val1 = tmp.val1;
}
#undef u
inline uint newnode(char c) {
int x = ++ tot;
nd[x] = node(c);
return x;
}
int join(int u , int v) {
if (!u || !v) return u | v;
int t = newnode(0);
if (nd[u].pri < nd[v].pri) {
nd[t] = nd[u];
nd[t].r = join(nd[u].r , v);
} else {
nd[t] = nd[v];
nd[t].l = join(u , nd[v].l);
}
upd(t);
return t;
}
int sum(uint u , int k) {
if (!k || !u) return 0;
if (nd[nd[u].l].sz >= k)
return sum(nd[u].l , k);
else {
int s = sum(nd[u].r , k - nd[nd[u].l].sz - 1);
s = (s * pw1[1] + nd[u].c - 'a');
s = (s * pw1[nd[nd[u].l].sz] + nd[nd[u].l].val1);
return s;
}
}
struct Treap {
int rt;
Treap() { rt = 0; }
inline void merge(Treap &x) {
rt = join(x.rt , rt);
}
};
inline bool check(uint u , uint v , int k) {
int x = sum(u , k) , y = sum(v , k);
return x == y;
}
inline int LCP(Treap &x , Treap &b) {
uint u = x.rt , v = b.rt;
int l = 1 , r = min(nd[u].sz , nd[v].sz);
int t = 0;
while (l <= r) {
int m = (l + r) >> 1;
if (check(u , v , m))
upmax(t , m) , l = m + 1;
else
r = m - 1;
}
return t;
}
inline void read(Treap &t) {
static int sta[maxS];
int top = 0 , pre;
char c = getchar();
while (!isalpha(c)) c = getchar();
while (isalpha(c)) {
pre = 0;
int u = newnode(c);
while (top && nd[sta[top]].pri > nd[u].pri) {
upd(sta[top]);
pre = sta[top --];
}
nd[u].l = pre;
if (top) nd[sta[top]].r = u;
sta[++ top] = u;
c = getchar();
}
while (top) upd(sta[top --]);
t.rt = sta[1];
}
Treap tag[maxs] , str[maxn] , s;
int val[maxs];
int ql , qr;
#define T int u = 1 , int l = 1 , int r = n
#define L lc , l , m
#define R rc , m + 1 , r
#define lc (u << 1)
#define rc (u << 1 | 1)
void B(T) {
if (l == r) {
tag[u] = str[l];
if (l != n)
val[u] = LCP(str[l] , str[l + 1]);
return;
}
int m = (l + r) >> 1;
B(L) , B(R);
val[u] = min(val[lc] , val[rc]);
}
inline void set_tag(int u , Treap t) {
val[u] += nd[t.rt].sz;
tag[u].merge(t);
}
inline void push(int u) {
if (!tag[u].rt)
return;
set_tag(lc , tag[u]);
set_tag(rc , tag[u]);
tag[u] = Treap();
}
void modi(T) {
if (ql <= l && r <= qr) {
set_tag(u , s);
return;
}
push(u);
int m = (l + r) >> 1;
if (ql <= m) modi(L);
if (qr > m) modi(R);
val[u] = min(val[lc] , val[rc]);
}
Treap get(T) {
if (l == r)
return tag[u];
push(u);
int m = (l + r) >> 1;
if (ql <= m)
return get(L);
return get(R);
}
void set(T) {
if (l == r)
return (void) (val[u] = qr);
int m = (l + r) >> 1;
push(u);
if (ql <= m)
set(L);
else
set(R);
val[u] = min(val[lc] , val[rc]);
}
void add(T) {
if (l == r)
return (void) (set_tag(u , s));
int m = (l + r) >> 1;
push(u);
if (ql <= m)
add(L);
else
add(R);
val[u] = min(val[lc] , val[rc]);
}
void input() {
nd[0] = node(0) , nd[0].sz = 0;
n = rd() , m = rd();
pw1[0] = 1;
rep (i , 1 , maxS - 7)
pw1[i] = pw1[i - 1] * 41;
rep (i , 1 , n)
read(str[i]);
B();
}
inline void reval(int l) {
Treap t1 , t2;
ql = l;
t1 = get();
ql = l + 1;
t2 = get();
ql = l , qr = LCP(t1 , t2);
set();
}
inline void insert() {
int l = rd() , r = rd();
read(s);
ql = r;
add();
if (l < r) {
ql = l , qr = r - 1;
modi();
}
if (l > 1)
reval(l - 1);
if (r < n)
reval(r);
}
int que(T) {
if (ql <= l && r <= qr)
return val[u];
int m = (l + r) >> 1 , t = inf;
push(u);
if (ql <= m) upmin(t , que(L));
if (qr > m) upmin(t , que(R));
return t;
}
inline void query() {
ql = rd() , qr = rd();
int ans;
if (ql == qr) {
Treap t = get();
ans = nd[t.rt].sz;
} else {
-- qr;
ans = que();
}
printf("%d\n" , ans);
}
void solve() {
rep (i , 1 , m) {
char cmd = rdch();
if (cmd == 'I')
insert();
else
query();
}
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}