Trie树/可持久化线段树


  神题啊……搞了我一下午= =(其实第233个提交也是我的)

  我一开始的思路:这个找kpm串的过程,其实就跟在AC自动机上沿fail倒着往下走是差不多的(看当前是哪些点的后缀,如果某个串的后缀是当前串,那它的fail就会指向这里)所以就在fail树上bfs一遍,然后找到所有的编号,排序后输出第k小……

  然后顺利地WA了 QAQ

  只好取膜拜题解……哦原来只要把每个串倒过来,建Trie树的时候,就相当于找当前这个串的子树!

  在子树中统计啊……so easy啦~dfs一遍,把儿子中的编号传给父亲啦~然后就会发现光荣TLE了>_>

  shen me gui!为什么呢?很简单啦,结点那么多,最坏情况下要把n个编号上传n次(比如有10W个相同的串,每个串都为 "aaa....aa"(10W个a))妥妥的TLE了。

  等等……刚刚好像说是子树查询第K大?dfs序不是很好吗!瞬间转成求区间第K大!可持久化线段树!

  ok,终于顺利AC……

 /**************************************************************
Problem: 3439
User: Tunix
Language: C++
Result: Accepted
Time:1240 ms
Memory:51688 kb
****************************************************************/ //BZOJ 3439
#include<vector>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define rep(i,n) for(int i=0;i<n;++i)
#define F(i,j,n) for(int i=j;i<=n;++i)
#define D(i,j,n) for(int i=j;i>=n;--i)
#define pb push_back
using namespace std;
inline int getint(){
int v=,sign=; char ch=getchar();
while(ch<''||ch>''){ if (ch=='-') sign=-; ch=getchar();}
while(ch>=''&&ch<=''){ v=v*+ch-''; ch=getchar();}
return v*sign;
}
const int N=1e5+,INF=~0u>>;
typedef long long LL;
/******************tamplate*********************/
struct Trie{
int ch[],num;
bool sign;
}T[N];
int cnt=,n,tot,pos[N];
inline int id(char c){return c-'a';}
vector<int>v[N];
void Insert(char *s,int num){
int x=,y;
D(i,strlen(s)-,){
y=id(s[i]);
if (T[x].ch[y]==)
T[x].ch[y]=++cnt;
x=T[x].ch[y];
}
T[x].sign=;
v[x].pb(num);
pos[num]=x;
}
int st[N],ed[N],a[N];
void dfs(int x){
st[x]=tot+;
rep(i,v[x].size()) a[++tot]=v[x][i];
rep(i,)
if (T[x].ch[i]!=)
dfs(T[x].ch[i]);
ed[x]=tot;
}
struct Tree{
int cnt,l,r;
}t[N*];
int root[N],num=;
#define mid (l+r>>1)
void update(int &o,int l,int r,int pos){
t[++num]=t[o], o=num, ++t[o].cnt;
if (l==r) return;
if (pos<=mid) update(t[o].l,l,mid,pos);
else update(t[o].r,mid+,r,pos);
}
int query(int i,int j,int rank){
i=root[i]; j=root[j];
int l=,r=n;
while(l!=r){
if (t[t[j].l].cnt-t[t[i].l].cnt>=rank)
r=mid,i=t[i].l,j=t[j].l;
else{
rank-=t[t[j].l].cnt-t[t[i].l].cnt;
l=mid+,i=t[i].r,j=t[j].r;
}
}
if (t[j].cnt-t[i].cnt<rank) return -;
return l;
}
#undef mid
char s[N];
int main(){
#ifndef ONLINE_JUDGE
freopen("3439.in","r",stdin);
freopen("3439.out","w",stdout);
#endif
n=getint();
F(i,,n){
scanf("%s",s);
Insert(s,i);
}
dfs();
#ifdef debug
F(i,,tot) printf("%d ",a[i]);puts("");
F(i,,n) printf("%d %d\n",st[pos[i]],ed[pos[i]]);
#endif
F(i,,tot){
root[i]=root[i-];
update(root[i],,n,a[i]);
}
#ifdef debug
F(i,,num) printf("%d %d %d %d\n",i,t[i].l,t[i].r,t[i].cnt);
#endif
int k;
F(i,,n){
k=getint();
int ans=query(st[pos[i]]-,ed[pos[i]],k);
// printf("%d\n",ans>n ? -1 : ans);
printf("%d\n",ans);
}
return ;
}

3439: Kpm的MC密码

Time Limit: 15 Sec  Memory Limit: 256 MB
Submit: 234  Solved: 113
[Submit][Status][Discuss]

Description

背景

想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的。。。),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了。。。

描述

Kpm当年设下的问题是这样的:

现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串。

系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每
一个ki,要求你求出列出的n个字符串中所有是si的kpm串的字符串的编号中第ki小的数,如果不存在第ki小的数,则用-1代替。(比如说给出的字符
串是cd,abcd,bcd,此时k1=2,那么”cd”的kpm串有”cd”,”abcd”,”bcd”,编号分别为1,2,3其中第2小的编号就是
2)(PS:如果你能在相当快的时间里回答完所有n个ki的查询,那么你就可以成功帮kpm进入MC啦~~)

Input

第一行一个整数 n 表示字符串的数目

接下来第二行到n+1行总共n行,每行包括一个字符串,第i+1行的字符串表示编号为i的字符串

接下来包括n行,每行包括一个整数ki,意义如上题所示

Output

包括n行,第i行包括一个整数,表示所有是si的kpm串的字符串的编号中第ki小的数

Sample Input

3
cd
abcd
bcd
2
3
1

Sample Output

2
-1
2

样例解释

“cd”的kpm 串有”cd”,”abcd”,”bcd”,编号为1,2,3,第2小的编号是

2,”abcd”的kpm串只有一个,所以第3小的编号不存在,”bcd”的kpm

串有”abcd”,”bcd”,第1小的编号就是2。

数据范围与约定

设所有字符串的总长度为len

对于100%的数据,1<=n<=100000,0

HINT

Source

[Submit][Status][Discuss]

【BZOJ】【3439】Kpm的MC密码的更多相关文章

  1. BZOJ 3439: Kpm的MC密码( trie + DFS序 + 主席树 )

    把串倒过来插进trie上, 那么一个串的kpm串就是在以这个串最后一个为根的子树, 子树k大值的经典问题用dfs序+可持久化线段树就可以O(NlogN)解决 --------------------- ...

  2. bzoj 3439 Kpm的MC密码(Trie+dfs序+主席树)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3439 [题意] 给定若干串,问一个串的作为其后缀的给定串集合中的第k小. [思路] 如 ...

  3. bzoj 3439: Kpm的MC密码 Trie+动态开点线段树

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=3439 题解: 首先我们发现这道题要查的是后缀不是前缀. 如果查前缀就可以迅速查找到字符串 ...

  4. BZOJ 3439: Kpm的MC密码 (trie+dfs序主席树)

    题意 略 分析 把串倒过来插进trietrietrie上, 那么一个串的kpmkpmkpm串就是这个串在trietrietrie上对应的结点的子树下面的所有字符串. 那么像 BZOJ 3551/354 ...

  5. BZOJ 3439 Kpm的MC密码

    倒着建trie,然后主席树来求子树第k大. #include<iostream> #include<cstdio> #include<cstring> #inclu ...

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

    题面 先把每个串反着插进$Trie$树 每个节点的子树内,可能有一些节点是某些字符串的开头 每个节点挂一棵权值线段树,记录这些节点对应的原来字符串的编号 查询的时候在线段树上二分即可 为了节省空间,使 ...

  7. 【BZOJ3439】 Kpm的MC密码 (TRIE+主席树)

    3439: Kpm的MC密码 Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记 ...

  8. BZOJ3439: Kpm的MC密码

    3439: Kpm的MC密码 Time Limit: 15 Sec  Memory Limit: 256 MBSubmit: 166  Solved: 79[Submit][Status] Descr ...

  9. 【BZOJ3439】Kpm的MC密码 Trie树+可持久化线段树

    [BZOJ3439]Kpm的MC密码 Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当 ...

随机推荐

  1. 关于overflow-y:scroll ios设备不流畅的问题

    最近做双创项目的时候因为页面有很多数据显示,所以打算让它Y轴方向滚动条的形式展现,但在测试阶段发现IOS设备滑动效果非常不理想: search by google之后找到解决办法: -webkit-o ...

  2. HUE 忘记密码

    解决方法: 启动HUE的Shell /opt/cloudera/parcels/CDH/lib/hue/build/env/bin/hue shell from django.contrib.auth ...

  3. ThinkPHP之中getlist方法实现数据搜索功能

    自己在ThinkPHP之中的model之中书写getlist方法,其实所谓的搜索功能无非就是数据库查询之中用到的like  %string%,或者其他的 字段名=特定值,这些sql语句拼接在and语句 ...

  4. mysql中存不进去json_encode格式的数据

    主要是因为json_encode格式的数据,中间带有\,在存入数据库的时候,会把反斜杠删除了. 所以,想要存进去的话,需要在外层调用一下函数addslashes();这个函数会在每个反斜杠的前面添加反 ...

  5. C# 代码重启windows服务

    ServiceController service = new ServiceController("EnergyRecordService"); protected void b ...

  6. [terry笔记]RMAN综合学习之恢复

    [terry笔记]RMAN综合学习之备份http://www.cnblogs.com/kkterry/p/3308405.html [terry笔记]RMAN综合学习之恢复 http://www.cn ...

  7. Map和HashMap

    通过查询JDK帮助文档,我们可以得知Map的说明.方法等 import java.util.Map; import java.util.HashMap; class Test{ public stat ...

  8. 转 在SQL Server中创建用户角色及授权(使用SQL语句)

     目录 要想成功访问 SQL Server 数据库中的数据 我们需要两个方面的授权 完整的代码示例 使用存储过程来完成用户创建 实例 要想成功访问 SQL Server 数据库中的数据, 我们需要两个 ...

  9. 自己的php函数库

    //判断数组中是否有元素为空的函数,支持多维数组,相似系统函数in_array(value,array,type) function is_null_array($arr) { if(!is_arra ...

  10. Android--获取App应用程序的大小

    Android对这种方法进行了封装,我们没有权限去调用这个方法,所以我们只能通过AIDL,然后利用Java的反射机制去调用系统级的方法. 下面上代码:(注释比较详细) /** * 作用:-----获取 ...