【bzoj3439】Kpm的MC密码 trie树+主席树

裸题,倒着建trie树,所有符合要求的串都在它的子树里,然后就是查询子树第k小了,用dfs序+主席树就可以了。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
#define maxn 300010

using namespace std;

int lch[maxn*20],rch[maxn*20],root[maxn],cnt[maxn*20];
int ch[maxn][26];
char s[maxn];
int in[maxn],out[maxn],id[maxn],a[maxn];
int head[maxn],next[maxn],to[maxn];
int tot,num,n,m;

void add(int x,int y)
{
	tot++;to[tot]=y;next[tot]=head[x];head[x]=tot;
}

void insert(int p)
{
	int len=strlen(s),x=0;
	for (int i=len-1;i>=0;i--)
	  if (ch[x][s[i]-'a']) x=ch[x][s[i]-'a'];
	  else ch[x][s[i]-'a']=++num,x=num;
	add(x,p);
}

void dfs(int x)
{
	int num=tot;
	for (int p=head[x];p;p=next[p]) a[++tot]=to[p];
	for (int i=0;i<26;i++)
	  if (ch[x][i]) dfs(ch[x][i]);
	for (int p=head[x];p;p=next[p]) in[to[p]]=num,out[to[p]]=tot;
}

int modify(int pre,int l,int r,int x)
{
	int now=++tot;
	if (l==r)
	{
		cnt[now]=cnt[pre]+1;lch[now]=rch[now]=0;
	}
	else
	{
		int mid=(l+r)/2;
		if (x<=mid)
		{
			rch[now]=rch[pre];lch[now]=modify(lch[pre],l,mid,x);
		}
		else
		{
			lch[now]=lch[pre];rch[now]=modify(rch[pre],mid+1,r,x);
		}
		cnt[now]=cnt[lch[now]]+cnt[rch[now]];
	}
	return now;
}

int query(int root1,int root2,int l,int r,int k)
{
	int mid=(l+r)/2;
	if (l==r) return l;
	if (cnt[root2]-cnt[root1]<k) return -1;
	if (cnt[lch[root2]]-cnt[lch[root1]]>=k) return query(lch[root1],lch[root2],l,mid,k);
	else return query(rch[root1],rch[root2],mid+1,r,k-(cnt[lch[root2]]-cnt[lch[root1]]));
}

int main()
{
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		scanf("%s",s);
		insert(i);
	}
	tot=0;
	dfs(0);
	tot=0;
	root[0]=lch[0]=rch[0]=cnt[0]=0;
	for (int i=1;i<=n;i++) root[i]=modify(root[i-1],1,n,a[i]);
	for (int i=1;i<=n;i++)
	{
		int k;
		scanf("%d",&k);
		printf("%d\n",query(root[in[i]],root[out[i]],1,n,k));
	}
	return 0;
}
    原文作者:Trie树
    原文地址: https://blog.csdn.net/u012288458/article/details/50040425
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注