标签:bzoj bzoj3439 trie树 可持久化线段树
题目大意:给定n个字符串,对于每个字符串求以这个字符串为后缀的字符串中第k小的编号
首先将字符串反转 那么就变成了对于每个字符串求以这个字符串为前缀的字符串中第k小的编号
然后考虑对字符串排序 那么对于每个字符串以它为前缀的字符串一定是连续的 那么就转化成了区间第k小 这个用可持久化线段树可以解决
排序自然不能直接排 既然是字符串 考虑Trie树+DFS即可 注意字符串有重复的 小心
#include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct Trie{ vector<int> num; Trie *son[26]; void* operator new (size_t size); }*root,*mempool,*C; struct Segtree{ Segtree *ls,*rs; int num; void* operator new (size_t size,Segtree *_,Segtree *__,int ___); }*tree[M],*_mempool,*G; int n,a[M],l[M],r[M],tot; char s[M]; void* Trie :: operator new (size_t size) { if(C==mempool) { C=new Trie[1<<15]; mempool=C+(1<<15); memset(C,0,sizeof(Trie)*(1<<15) ); } return C++; } void* Segtree :: operator new (size_t size,Segtree *_,Segtree *__,int ___) { if(G==_mempool) { G=new Segtree[1<<15]; _mempool=G+(1<<15); memset(G,0,sizeof(Segtree)*(1<<15) ); } G->ls=_; G->rs=__; G->num=___; return G++; } void Insert(Trie*&p,char *str,int pos) { if(!p) p=new Trie; if(!*str) { p->num.push_back(pos); return ; } Insert(p->son[(*str)-'a'],str+1,pos); } void DFS(Trie *p) { int i; vector<int>::iterator it; p->num.begin(); int temp=tot+1; for(it=p->num.begin();it!=p->num.end();it++) { a[++tot]=*it; l[*it]=temp; } for(i=0;i<26;i++) if(p->son[i]) DFS(p->son[i]); for(it=p->num.begin();it!=p->num.end();it++) r[*it]=tot; } Segtree* Build_Tree(Segtree *p,int x,int y,int val) { int mid=x+y>>1; if(x==y) return new (0x0,0x0,p->num+1) Segtree; if(val<=mid) return new (Build_Tree(p->ls,x,mid,val),p->rs,p->num+1) Segtree; else return new (p->ls,Build_Tree(p->rs,mid+1,y,val),p->num+1) Segtree; } int Get_Ans(Segtree *p1,Segtree *p2,int x,int y,int k) { int mid=x+y>>1; if(x==y) return mid; int temp=p2->ls->num-p1->ls->num; if(k<=temp) return Get_Ans(p1->ls,p2->ls,x,mid,k); else return Get_Ans(p1->rs,p2->rs,mid+1,y,k-temp); } int main() { int i,j,k; cin>>n; for(i=1;i<=n;i++) { scanf("%s",s+1); int temp=strlen(s+1); for(j=1;j<<1<=temp;j++) swap(s[j],s[temp+1-j]); Insert(root,s+1,i); } DFS(root); tree[0]=new (0x0,0x0,0) Segtree; tree[0]->ls=tree[0]->rs=tree[0]; for(i=1;i<=n;i++) tree[i]=Build_Tree(tree[i-1],1,n,a[i]); for(i=1;i<=n;i++) { scanf("%d",&k); if(k>r[i]-l[i]+1) puts("-1"); else printf("%d\n", Get_Ans(tree[l[i]-1],tree[r[i]],1,n,k) ); } }
BZOJ 3439 Kpm的MC密码 Trie树+可持久化线段树
标签:bzoj bzoj3439 trie树 可持久化线段树
原文地址:http://blog.csdn.net/popoqqq/article/details/41207523