[BZOJ3439]Kpm的MC密码

题目大意:
  给定$n(n\leq10^5)$个字符串$s_{1\sim n}$,$n$次询问,每次询问所有满足$s_i$是$t$的后缀的$t$中,编号第$k_i$小的$t$的编号。

思路:
  倒着建字典树,根据DFS序建立主席树,维护每个区间内编号出现次数。

 1 #include<list>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<cstring>
 5 #include<algorithm>
 6 inline int getint() {
 7     register char ch;
 8     while(!isdigit(ch=getchar()));
 9     register int x=ch^'0';
10     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
11     return x;
12 }
13 const int N=100001,logN=18,S=26;
14 int n;
15 class FotileTree {
16     private:
17         struct Node {
18             int val,left,right,vis;
19         };
20         Node node[N*logN];
21         int sz,new_node(const int &p,const int &id) {
22             node[++sz]=node[p];
23             node[sz].vis=id;
24             return sz;
25         }
26     public:
27         int root[N];
28         void modify(int &p,const int &b,const int &e,const int &x,const int &y,const int &id) {
29             if(node[p].vis!=id) p=new_node(p,id);
30             node[p].val+=y;
31             if(b==e) return;
32             const int mid=(b+e)>>1;
33             if(x<=mid) modify(node[p].left,b,mid,x,y,id);
34             if(x>mid) modify(node[p].right,mid+1,e,x,y,id);
35         }
36         int query(const int &p,const int &q,const int &b,const int &e,const int &k) {
37             if(node[q].val-node[p].val<k) return -1;
38             if(b==e) return b;
39             const int mid=(b+e)>>1;
40             if(node[node[q].left].val-node[node[p].left].val>=k) return query(node[p].left,node[q].left,b,mid,k);
41             return query(node[p].right,node[q].right,mid+1,e,k-(node[node[q].left].val-node[node[p].left].val));
42         }
43 };
44 FotileTree t;
45 class Trie {
46     private:
47         int pos[N],ch[N][S],par[N],dfn[N],size[N],cnt;
48         std::list<int> val[N];
49         int sz,new_node(const int &p) {
50             par[++sz]=p;
51             return sz;
52         }
53         int idx(const char &c) const {
54             return c-'a';
55         }
56         void push_up(const int &p) {
57             size[p]=1;
58             for(register int i=0;i<S;i++) size[p]+=size[ch[p][i]];
59         }
60     public:
61         void insert(const char s[],const int &id) {
62             int u=0;
63             for(register int i=0;s[i];i++) {
64                 u=ch[u][idx(s[i])]=ch[u][idx(s[i])]?:new_node(u);
65             }
66             val[pos[id]=u].push_back(id);
67             for(;u;u=par[u]) push_up(u);
68         }
69         void dfs(const int &x) {
70             dfn[x]=cnt++;
71             if(dfn[x]) t.root[dfn[x]]=t.root[dfn[x]-1];
72             for(register std::list<int>::iterator i=val[x].begin();i!=val[x].end();i++) {
73                 t.modify(t.root[dfn[x]],1,n,*i,1,dfn[x]);
74             }
75             for(int i=0;i<S;i++) {
76                 if(ch[x][i]) dfs(ch[x][i]);
77             }
78         }
79         int query(const int &id,const int &k) {
80             return t.query(t.root[dfn[pos[id]]-1],t.root[dfn[pos[id]]+size[pos[id]]-1],1,n,k);
81         }
82 };
83 Trie trie;
84 char s[N];
85 int main() {
86     n=getint();
87     for(register int i=1;i<=n;i++) {
88         scanf("%s",s);
89         std::reverse(&s[0],&s[strlen(s)]);
90         trie.insert(s,i);
91     }
92     trie.dfs(0);
93     for(register int i=1;i<=n;i++) {
94         printf("%d\n",trie.query(i,getint()));
95     }
96     return 0;
97 }

 

posted @ 2018-03-14 08:59  skylee03  阅读(176)  评论(0编辑  收藏  举报