码迷,mamicode.com
首页 > 其他好文 > 详细

BZOJ 3439 Kpm的MC密码 Trie树+可持久化线段树

时间:2014-11-17 14:07:57      阅读:140      评论:0      收藏:0      [点我收藏+]

标签: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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!