BZOJ 3439 Kpm的MC密码 (Trie树+线段树合并)

题面

先把每个串反着插进$Trie$树

每个节点的子树内,可能有一些节点是某些字符串的开头

每个节点挂一棵权值线段树,记录这些节点对应的原来字符串的编号

查询的时候在线段树上二分即可

为了节省空间,使用线段树合并

  1 #include <vector>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #define N1 100100
  6 #define M1 (N1*3)
  7 #define idx(X) (X-'a')
  8 using namespace std;
  9 
 10 char str[M1];
 11 int a[N1],n;
 12 
 13 struct SEG{
 14 int sz[N1*100],ls[N1*100],rs[N1*100],root[M1],tot;
 15 inline void pushup(int rt){ sz[rt]=sz[ls[rt]]+sz[rs[rt]]; }
 16 void update(int x,int l,int r,int &rt,int w)
 17 {
 18     if(!rt) rt=++tot;
 19     if(l==r){ sz[rt]+=w; return; }
 20     int mid=(l+r)>>1; 
 21     if(x<=mid) update(x,l,mid,ls[rt],w);
 22     else update(x,mid+1,r,rs[rt],w);
 23     pushup(rt);
 24 }
 25 int merge(int l,int r,int r1,int r2)
 26 {
 27     if(!r1||!r2) return r1+r2;
 28     int mid=(l+r)>>1,rt=++tot;
 29     //sz[rt]=sz[r1]+sz[r2];
 30     ls[rt]=merge(l,mid,ls[r1],ls[r2]);
 31     rs[rt]=merge(mid+1,r,rs[r1],rs[r2]);
 32     pushup(rt);
 33     return rt;
 34 }
 35 int query(int l,int r,int rt,int K)
 36 { 
 37     if(K>sz[rt]) return -1;
 38     if(l==r) return l;
 39     int mid=(l+r)>>1;
 40     if(K>sz[ls[rt]]) return query(mid+1,r,rs[rt],K-sz[ls[rt]]);
 41     else return query(l,mid,ls[rt],K);
 42 }
 43 }s;
 44 
 45 namespace Trie{
 46 int ch[M1][26],dep[M1],fa[M1],tot;
 47 vector<int>ed[M1];
 48 void insert(int len,int id,int *pos)
 49 {
 50     int x=0,c,i;
 51     for(i=len;i>=1;i--)
 52     {
 53         c=idx(str[i]);
 54         if(!ch[x][c]) 
 55             ch[x][c]=++tot,dep[tot]=dep[x]+1,fa[tot]=x;
 56         x=ch[x][c];
 57     }
 58     ed[x].push_back(id);
 59     pos[id]=x;
 60 }
 61 int hs[M1],que[M1];
 62 void build()
 63 {
 64     int i,j,id,x;
 65     for(i=1;i<=tot;i++) hs[dep[i]]++;
 66     for(i=1;i<=tot;i++) hs[i]+=hs[i-1];
 67     for(i=1;i<=tot;i++) que[hs[dep[i]]--]=i;
 68     for(i=tot;i>=1;i--)
 69     {
 70         x=que[i];
 71         for(j=0;j<ed[x].size();j++)
 72         {
 73             id=ed[x][j];
 74             s.update(id,1,n,s.root[x],1);
 75         }
 76     }
 77     for(i=tot;i>=1;i--)
 78     {
 79         x=que[i];
 80         s.root[fa[x]]=s.merge(1,n,s.root[x],s.root[fa[x]]);
 81     }
 82 }
 83 };
 84 
 85 int pos[M1];
 86 int main()
 87 {
 88     scanf("%d",&n);
 89     int i,j,k,cnt,L;
 90     for(i=1;i<=n;i++)
 91     {
 92         scanf("%s",str+1);
 93         L=strlen(str+1);
 94         Trie::insert(L,i,pos);
 95     }
 96     Trie::build();
 97     for(i=1;i<=n;i++)
 98     {
 99         scanf("%d",&a[i]);
100         printf("%d\n",s.query(1,n,s.root[pos[i]],a[i]));
101     }
102     return 0;
103 }

 

posted @ 2019-01-23 14:15  guapisolo  阅读(150)  评论(0编辑  收藏  举报