题目链接
给出 n n n 个字符串, m m m 个操作,操作有两种,一种是交换 i , j i,j i,j 两个字符串的位置,一种是查询 [ l , r ] [l,r] [l,r] 范围内与给出的字符串 q q q 的最长公共前缀 ( L C P ) (LCP) (LCP) 至少为 k k k 的字符串有多少个。
对给出的字符串建一棵 T r i e Trie Trie,那么以某个串 a a a 在 T r i e Trie Trie 上的节点的那颗子树下面的子串的 L C P LCP LCP 就至少是 a a a 了,把结点转成 d f s dfs dfs 序,问题就转化成了带修改的二维数点, c d q cdq cdq 即可,复杂度 O ( n l o g 2 n ) O(nlog^2n) O(nlog2n)。
代码:
#include
#include
#include
using namespace std;
using namespace __gnu_cxx;
using namespace __gnu_pbds;
#define debug(a) cout << #a": " << a << endl;
#define mst(a, b) memset(a, b, sizeof(a))
#define ALL(x) x.begin(), x.end()
#define lc rt << 1
#define rc rt << 1 | 1
#define X first
#define Y second
inline int lowbit(int x) { return x & -x; }
typedef long long ll;
typedef long long LL;
typedef unsigned long long ULL;
typedef double db;
typedef pair<int, int> pii;
typedef pair<int, LL> pil;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int maxn = 2e3 + 10;
const int maxm = 4e3 + 10;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
const int mod = 998244353;
const db eps = 1e-11;
const db pi = acos(-1.0);
struct P {
int op, qt, ql, qr, val;
}p[M];
char s[N];
int ch[26][N];
int id[N];
int dfn[N];
int en[N];
int qans[N];
int idans[M];
int tot;
int totDfn;
int bit[N];
void update(int pos, int val) {
++pos;
for (; pos < N; pos += lowbit(pos))
bit[pos] += val;
}
int Qu(int pos) {
int res = 0;
++pos;
for (; pos; pos -= lowbit(pos))
res += bit[pos];
return res;
}
int ins(int len) {
int root = 0;
for (int i = 1; i <= len; i++) {
int idx = s[i] - 'a';
int& nxt = ch[idx][root];
if (!nxt)
nxt = ++tot;
root = nxt;
}
return root;
}
int query(int len) {
int root = 0;
for (int i = 1; i <= len; i++) {
int idx = s[i] - 'a';
if (!ch[idx][root])
return -1;
root = ch[idx][root];
}
return root;
}
void dfs(int u) {
dfn[u] = ++totDfn;
for (int i = 0; i < 26; i++) if (ch[i][u])
dfs(ch[i][u]);
en[u] = totDfn;
}
void cdq(int L, int R) {
if (L >= R)
return ;
int mid = L + R >> 1;
cdq(L, mid);
cdq(mid + 1, R);
for (int i = mid + 1, j = L; i <= R; i++) {
for (; j <= mid && p[j].qr <= p[i].qr; j++) if (p[j].op == 1) {
update(p[j].ql, p[j].val);
}
if (p[i].op == 2)
qans[idans[p[i].qt]] += Qu(p[i].ql) * p[i].val;
}
for (int i = mid + 1, j = L; i <= R; i++) {
for (; j <= mid && p[j].qr <= p[i].qr; j++) if (p[j].op == 1) {
update(p[j].ql, -p[j].val);
}
}
sort(p + L, p + R + 1, [](P a, P b) {
return a.qr < b.qr;
});
}
int main() {
#ifdef purple_bro
freopen("in.txt", "r", stdin);
#endif
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> s + 1;
int len = strlen(s + 1);
id[i] = ins(len);
}
dfs(0);
int q = 0;
int qu = 0;
for (int i = 1; i <= n; i++)
p[++q] = {1, 1, i, dfn[id[i]], 1};
for (int i = 1; i <= m; i++) {
int opt;
cin >> opt;
if (opt == 1) {
int x, y;
cin >> x >> y;
p[++q] = {opt, i, x, dfn[id[x]], -1};
p[++q] = {opt, i, y, dfn[id[y]], -1};
swap(id[x], id[y]);
p[++q] = {opt, i, x, dfn[id[x]], 1};
p[++q] = {opt, i, y, dfn[id[y]], 1};
} else {
int k, l, r;
cin >> s + 1 >> k >> l >> r;
int d = query(k);
idans[i] = ++qu;
if (d == -1)
qans[qu] = 0;
else {
p[++q] = {opt, i, r, en[d], 1};
p[++q] = {opt, i, l - 1, dfn[d] - 1, 1};
p[++q] = {opt, i, l - 1, en[d], -1};
p[++q] = {opt, i, r, dfn[d] - 1, -1};
}
}
}
cdq(1, q);
for (int i = 1; i <= qu; i++)
cout << qans[i] << "\n";
return 0;
}