[BZOJ 3439]Kpm的MC密码

Description

题库链接

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

$1\leq n\leq 1000000,\sum\limits_{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('\n'))
#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;
}
posted @ 2018-02-05 21:39  NaVi_Awson  阅读(146)  评论(0编辑  收藏  举报