• [BZOJ 3439]Kpm的MC密码


    Description

    题库链接

    给出 (n) 个字符串,从 (1sim n) 编号。问对于每个字符串,以其作为后缀的第 (K_i) 小的字符串编号为多少。

    (1leq nleq 1000000,sumlimits_{i=1}^n lenth(string(i))leq 300000)

    Solution

    按照套路,把后缀变为前缀,显然是可以在 (Trie) 树上解决这个问题。

    而对于查询第 (K) 小,我们可以每个节点开一个权值线段树,遍历字符串时,就将路径上的权值线段树更新。

    其他的就是线段树和 (Trie) 树的操作了。

    Code

    //It is made by Awson on 2018.2.5
    #include <bits/stdc++.h>
    #define LL long long 
    #define dob complex<double>
    #define Abs(a) ((a) < 0 ? (-(a)) : (a))
    #define Max(a, b) ((a) > (b) ? (a) : (b))
    #define Min(a, b) ((a) < (b) ? (a) : (b))
    #define Swap(a, b) ((a) ^= (b), (b) ^= (a), (a) ^= (b))
    #define writeln(x) (write(x), putchar('
    '))
    #define lowbit(x) ((x)&(-(x)))
    using namespace std; 
    const int N = 300000;
    const int M = 1000000;
    void read(int &x) {
        char ch; bool flag = 0;
        for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
        for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
        x *= 1-2*flag;
    }
    void print(int x) {if (x > 9) print(x/10); putchar(x%10+48); }
    void write(int x) {if (x < 0) putchar('-'); print(Abs(x)); }
    
    int n, k, ans[M+5];
    char c[N+5];
    struct Segment_tree {
        int root[N+5], ch[N*20+5][2], key[N*20+5], pos;
        void insert(int &o, int l, int r, int loc) {
            if (!o) o = ++pos; ++key[o]; if (l == r) return;
            int mid = (l+r)>>1;
            if (loc <= mid) insert(ch[o][0], l, mid, loc);
            else insert(ch[o][1], mid+1, r, loc);
        }
        int query(int o, int l, int r, int k) {
            if (l == r) return l;
            if (key[o] < k) return -1; int mid = (l+r)>>1;
            if (key[ch[o][0]] < k) return query(ch[o][1], mid+1, r, k-key[ch[o][0]]);
            else return query(ch[o][0], l, mid, k);
        }
    }T;
    struct Trie {
        int ch[N+5][26], pos;
        void insert(int id) {
            int len = strlen(c), u = 0;
            for (int i = len-1; i >= 0; i--) {
                if (ch[u][c[i]-'a'] == 0) ch[u][c[i]-'a'] = ++pos;
                u = ch[u][c[i]-'a']; T.insert(T.root[u], 1, n, id);
            }
            ans[id] = u;
        }
    }Tr;
    
    void work() {
        read(n);
        for (int i = 1; i <= n; i++) {
            scanf("%s", c); Tr.insert(i);
        }
        for (int i = 1; i <= n; i++) {
            read(k); writeln(T.query(T.root[ans[i]], 1, n, k));
        }
    }
    int main() {
        work(); return 0;
    }
  • 相关阅读:
    相对定位和绝对定位
    一切重新开始
    Oracle Profile 使用
    使用javamail发送邮件错误:550 5.7.1 Unable to relay
    gvim 备份文件去除 配置
    解决Maven中OutOfMemory错误
    sqlplus启动后的环境SQLPATH的设置
    ORA-30004 错误处理
    oracle 锁表查询及解决、表字段查询
    如何进行软件架构设计
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/8419519.html
Copyright © 2020-2023  润新知