首页 > 代码库 > [BZOJ3439]Kpm的MC密码

[BZOJ3439]Kpm的MC密码

看到后缀,就想到把所有串反过来插入trie中

建好trie之后dfs,答案其实就是当前结点的子树中的第k大

按dfs的顺序给节点编号,把问题转化为求区间第k大

那么就用可持久化线段树就好了

 

 1 #include<stdio.h>
 2 #include<vector>
 3 #include<string.h>
 4 using namespace std;
 5 struct trienode{
 6     int ch[26];
 7     vector<int>ids;
 8 }trie[300010];
 9 struct seg{
10     int lson,rson,size;
11 }tr[2000010];
12 int n,trietot,sttot,clk,root[100010],ans[100010],ki[100010];
13 void trieinsert(int id,int x,char*s,int p){
14     if(p<0){
15         trie[x].ids.push_back(id);
16         return;
17     }
18     if(trie[x].ch[s[p]-a]==0){
19         trietot++;
20         trie[x].ch[s[p]-a]=trietot;
21     }
22     trieinsert(id,trie[x].ch[s[p]-a],s,p-1);
23 }
24 void stinsert(int preroot,int root,int l,int r,int v){
25     tr[root].size=tr[preroot].size+1;
26     if(l==r)return;
27     int mid=(l+r)>>1;
28     sttot++;
29     if(v<=mid){
30         tr[root].lson=sttot;
31         tr[root].rson=tr[preroot].rson;
32         stinsert(tr[preroot].lson,sttot,l,mid,v);
33     }else{
34         tr[root].lson=tr[preroot].lson;
35         tr[root].rson=sttot;
36         stinsert(tr[preroot].rson,sttot,mid+1,r,v);
37     }
38 }
39 int stquery(int lroot,int rroot,int l,int r,int k){
40     if(tr[rroot].size-tr[lroot].size<k)return-1;
41     if(l==r)return l;
42     int mid=(l+r)>>1,d=tr[tr[rroot].lson].size-tr[tr[lroot].lson].size;
43     if(k<=d)
44         return stquery(tr[lroot].lson,tr[rroot].lson,l,mid,k);
45     else
46         return stquery(tr[lroot].rson,tr[rroot].rson,mid+1,r,k-d);
47 }
48 void dfs(int x){
49     int l,i;
50     l=clk;
51     for(i=0;i<trie[x].ids.size();i++){
52         clk++;
53         sttot++;
54         root[clk]=sttot;
55         stinsert(root[clk-1],sttot,1,n,trie[x].ids[i]);
56     }
57     for(i=0;i<26;i++){
58         if(trie[x].ch[i])dfs(trie[x].ch[i]);
59     }
60     for(i=0;i<trie[x].ids.size();i++){
61         ans[trie[x].ids[i]]=stquery(root[l],root[clk],1,n,ki[trie[x].ids[i]]);
62     }
63 }
64 char s[300010];
65 int main(){
66     int i;
67     scanf("%d",&n);
68     for(i=1;i<=n;i++){
69         scanf("%s",s);
70         trieinsert(i,0,s,strlen(s)-1);
71     }
72     for(i=1;i<=n;i++)scanf("%d",ki+i);
73     dfs(0);
74     for(i=1;i<=n;i++)printf("%d\n",ans[i]);
75 }

 

[BZOJ3439]Kpm的MC密码