P9016 [USACO23JAN] Find and Replace G 题解
从后往前考虑每次替换,同时用
在建树的时候,同样的子树不用再复制一份,而是直接建边,这样虽然总点数可能高达
具体来说,当前考虑的是第
结点信息要维护树的大小,为防止溢出不要超过
因为是二叉树,可以像线段树这样查询:途径的结点中是
总时间复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 1e18;
const int N = 200105;
struct Node {
char v;
int lc, rc;
LL sz;
} tr[N];
int root[26], ck;
char c[N];
string s[N];
void query(int u, LL l, LL r) {
if (r <= 0 || l > tr[u].sz) return;
if (tr[u].v == '#') {
query(tr[u].lc, l, r);
query(tr[u].rc, l - tr[tr[u].lc].sz, r - tr[tr[u].lc].sz);
} else {
putchar(tr[u].v);
}
}
int main() {
LL l, r, n;
cin >> l >> r >> n;
for (int i = 1; i <= n; i++) cin >> c[i] >> s[i];
for (int i = 0; i < 26; i++) {
tr[++ck] = {char('a' + i), 0, 0, 1};
root[i] = ck;
}
for (int i = n; i >= 1; i--) {
int now = 0;
for (auto x : s[i]) {
x -= 'a';
if (now == 0)
now = root[x];
else {
tr[++ck] = {'#', now, root[x], min(INF, tr[now].sz + tr[root[x]].sz)};
now = ck;
}
}
root[c[i] - 'a'] = now;
}
query(root[0], l, r);
putchar('\n');
return 0;
}