(A)[EPXLQ2024 fall round] 风吹起了从前
题意
给定 \(n\) 个字符串 \(a_1\) 到 \(a_n\)。第 \(i\) 个字符串拥有一个深度值 \(r_i\),有一个价值 \(v_i\)。
再给你 \(m\) 次询问,每次给出一个字符串 \(t\) 和深度 \(d\),求以 \(t\) 为前缀且深度值小于 \(d\) 的字符串价值之和。
Soluion
显然要使用字典树来处理,这道题可持久化字典树可以实现,但未免有点小题大做,本题解用普通字典树来实现。
首先思考,若每次询问的 \(d\) 单调不降该如何处理。
显然,先将字符串 \(a\) 按 \(r\) 从小到大排序,使用一个指针 \(pos\) 表示当前把几个字符串放入了字典树中。对于每次询问,不断将字符串放入字典树(在代码中即 ++pos
)直到 \(a_{pos} > d\),然后求值即可。
那么,\(d\) 不是单调不降的该怎么办呢?
因为本题不强制在线,所以直接将询问离线下来,排序使得 \(d\) 即可。
其他疑问见代码。
代码
//written by Naught
#include <bits/stdc++.h>
using namespace std;typedef long long ll;
#define Maxn 20005
#define Maxm 200005
#define Maxlen 105
#define fo(i, l, r) for (int i = l; i <= r; ++i)struct A
{int r, val/*, id*/;char s[Maxlen];
}a[Maxn];struct Query
{int div, id;char s[Maxlen];
}q[Maxm];struct Trie
{int son[30];ll sum;
}t[Maxn*Maxlen];int cnt = 1;
int n, m, pos = 1;
ll ans[Maxm];void Insert(char *s, int val)
{int p = 0, len = strlen(s);fo(i, 0, len-1){int ch = s[i]-'a';if(t[p].son[ch] == 0) t[p].son[ch] = cnt++;p = t[p].son[ch];t[p].sum += val;}
}ll find(char *s)
{int p = 0, len = strlen(s);fo(i, 0, len-1){int ch = s[i]-'a';if(t[p].son[ch] == 0) return 0;p = t[p].son[ch];}return t[p].sum;
}signed main()
{scanf("%d%d", &n, &m);fo(i, 1, n) scanf("%d%d%s", &a[i].r, &a[i].val, a[i].s);sort(a+1, a+n+1, [](A x, A y) {return x.r < y.r;});fo(i, 1, m) scanf("%d%s", &q[i].div, q[i].s), q[i].id = i;sort(q+1, q+m+1, [](Query x, Query y) {return x.div < y.div;});fo(i, 1, m){while(pos <= n && a[pos].r <= q[i].div) Insert(a[pos].s, a[pos].val), ++pos;ans[q[i].id] = find(q[i].s); }fo(i, 1, m) printf("%lld\n", ans[i]);return 0;
}
Tips
\(100 \times 10^9\) 会爆 int
,记得开long long
。