题解:(A)[EPXLQ2024 fall round] 风吹起了从前

(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

posted @ 2024-12-15 21:34  naughty_Naught  阅读(23)  评论(0编辑  收藏  举报