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;
}