[BZOJ3439]Kpm的MC密码
题目大意:
给定$n(n\leq10^5)$个字符串$s_{1\sim n}$,$n$次询问,每次询问所有满足$s_i$是$t$的后缀的$t$中,编号第$k_i$小的$t$的编号。
思路:
倒着建字典树,根据DFS序建立主席树,维护每个区间内编号出现次数。
#include<list> #include<cstdio> #include<cctype> #include<cstring> #include<algorithm> inline int getint() { register char ch; while(!isdigit(ch=getchar())); register int x=ch^'0'; while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0'); return x; } const int N=100001,logN=18,S=26; int n; class FotileTree { private: struct Node { int val,left,right,vis; }; Node node[N*logN]; int sz,new_node(const int &p,const int &id) { node[++sz]=node[p]; node[sz].vis=id; return sz; } public: int root ; void modify(int &p,const int &b,const int &e,const int &x,const int &y,const int &id) { if(node[p].vis!=id) p=new_node(p,id); node[p].val+=y; if(b==e) return; const int mid=(b+e)>>1; if(x<=mid) modify(node[p].left,b,mid,x,y,id); if(x>mid) modify(node[p].right,mid+1,e,x,y,id); } int query(const int &p,const int &q,const int &b,const int &e,const int &k) { if(node[q].val-node[p].val<k) return -1; if(b==e) return b; const int mid=(b+e)>>1; if(node[node[q].left].val-node[node[p].left].val>=k) return query(node[p].left,node[q].left,b,mid,k); return query(node[p].right,node[q].right,mid+1,e,k-(node[node[q].left].val-node[node[p].left].val)); } }; FotileTree t; class Trie { private: int pos ,ch [S],par ,dfn ,size ,cnt; std::list<int> val ; int sz,new_node(const int &p) { par[++sz]=p; return sz; } int idx(const char &c) const { return c-'a'; } void push_up(const int &p) { size[p]=1; for(register int i=0;i<S;i++) size[p]+=size[ch[p][i]]; } public: void insert(const char s[],const int &id) { int u=0; for(register int i=0;s[i];i++) { u=ch[u][idx(s[i])]=ch[u][idx(s[i])]?:new_node(u); } val[pos[id]=u].push_back(id); for(;u;u=par[u]) push_up(u); } void dfs(const int &x) { dfn[x]=cnt++; if(dfn[x]) t.root[dfn[x]]=t.root[dfn[x]-1]; for(register std::list<int>::iterator i=val[x].begin();i!=val[x].end();i++) { t.modify(t.root[dfn[x]],1,n,*i,1,dfn[x]); } for(int i=0;i<S;i++) { if(ch[x][i]) dfs(ch[x][i]); } } int query(const int &id,const int &k) { return t.query(t.root[dfn[pos[id]]-1],t.root[dfn[pos[id]]+size[pos[id]]-1],1,n,k); } }; Trie trie; char s ; int main() { n=getint(); for(register int i=1;i<=n;i++) { scanf("%s",s); std::reverse(&s[0],&s[strlen(s)]); trie.insert(s,i); } trie.dfs(0); for(register int i=1;i<=n;i++) { printf("%d\n",trie.query(i,getint())); } return 0; }
- [BZOJ 3439]Kpm的MC密码
- bzoj 3439: Kpm的MC密码
- BZOJ3439 Kpm的MC密码
- 【bzoj3439】Kpm的MC密码 可持久化Trie树
- BZOJ 3439: Kpm的MC密码( trie + DFS序 + 主席树 )
- BZOJ-3439 Kpm的MC密码
- 【BZOJ3439】 Kpm的MC密码 (TRIE+主席树)
- bzoj 3439: Kpm的MC密码 Trie+动态开点线段树
- [BZOJ 3439]Kpm的MC密码
- BZOJ3439 Kpm的MC密码(可持久化trie)
- bzoj 3439 Kpm的MC密码(Trie+dfs序+主席树)
- 【bzoj3439】kpm的mc密码 题解
- bzoj 3439: Kpm的MC密码
- BZOJ 3439 Kpm的MC密码
- 【BZOJ 3439】Kpm的MC密码 主席树+trie树
- [BZOJ]3439: Kpm的MC密码 trie树+主席树(线段树合并)
- 【BZOJ3439】Kpm的MC密码 Trie+dfs序+可持久化线段树
- 【BZOJ3439】Kpm的MC密码,trie树+dfs序+主席树
- 【BZOJ】【3439】Kpm的MC密码
- bzoj3439 Kpm的MC密码