BZOJ3439: Kpm的MC密码
来源:互联网 发布:免费遥感数据 编辑:程序博客网 时间:2024/04/29 08:40
BZOJ3439: Kpm的MC密码
Tire树·dfs序·主席树
题解:
把字符串反过来,后缀变成前缀,扔进Tire树里。
以一个字符串结束点为根的子树中的单词都是它的Kpm串。要求其中第K大的编号。
求Tire树的dfs序,子树变成连续的区间,套主席树的区间第K大。
注意:有相同的字符串。
不仅Tire树结束标记要用vector了,而且主席树插入的时候也不能直接clone上一层的了(那样cnt就不对了),而是本层第一个先clone上一层,后面都clone这一层。另外,如果这一层没有,不要忘了root[i]=root[i-1].
一开始以为本身不算,写了个rank处理了一下,后来发现不用。。。
道理都懂,然而还是写了1.5h+
看着这些注释的调试输出,你能感受到我的绝望吗QWQ
Code:
#include <algorithm>#include <iostream>#include <cstring>#include <cstdio>#include <vector>#define D(x) cout<<#x<<" = "<<x<<" "#define E cout<<endlusing namespace std;const int N = 100005;int n,m; char str[N];int pos[N],ptr[N],end[N],tim,root[N];vector<int> lab[N]; int relib[N];namespace Tire{ int ch[N][26]; int sz=1; void rev(char s[]){ int len=strlen(s); for(int i=0;i<len/2;i++) swap(s[i],s[len-i-1]); } void insert(char s[],int id){ int x=1; for(int i=0;s[i];i++){ if(!ch[x][s[i]-'a']) ch[x][s[i]-'a']=++sz; x=ch[x][s[i]-'a']; } lab[x].push_back(id); relib[id]=x; } void dfs(int x){ pos[x]=++tim; ptr[pos[x]]=x; for(int i=0;i<26;i++) if(ch[x][i]) { dfs(ch[x][i]); } end[x]=tim; }}namespace Tree{ int sz,lch[N*20],rch[N*20],cnt[N*20]; void clone(int x,int t){ lch[x]=lch[t]; rch[x]=rch[t]; cnt[x]=cnt[t]; } void insert(int &x,int t,int l,int r,int p){// D(l); D(r); D(p); E; x=++sz; clone(x,t); cnt[x]++; // D(cnt[x]); E; if(l!=r){ int mid=(l+r)>>1; if(p<=mid) insert(lch[x],lch[t],l,mid,p); else insert(rch[x],rch[t],mid+1,r,p); } }// int rank(int a,int b,int l,int r,int p){// if(l==r) return 1;// int mid=(l+r)>1;// if(p<=mid) return rank(lch[a],lch[b],l,mid,p);// else return rank(rch[a],rch[b],mid+1,r,p) + cnt[lch[b]]-cnt[lch[a]];// } int query(int a,int b,int l,int r,int k){// D(a); D(b); D(l); D(r); D(k); E; if(cnt[b]-cnt[a] < k) return -1; if(l==r) return l; int mid=(l+r)>>1;// D(lch[b]); D(lch[a]); E; int lsz=cnt[lch[b]]-cnt[lch[a]]; // D(cnt[lch[b]]); D(cnt[lch[a]]); D(lsz); E; if(k<=lsz) return query(lch[a],lch[b],l,mid,k); else return query(rch[a],rch[b],mid+1,r,k-lsz); }}int main(){ freopen("a.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%s",str); Tire::rev(str); Tire::insert(str,i); } Tire::dfs(1);// for(int i=1;i<=Tire::sz;i++){// D(pos[i]); D(end[i]); E;// } for(int i=1;i<=tim;i++){// D(i); E; if(lab[ptr[i]].size()){ int pre=root[i-1]; for(int j=0;j<lab[ptr[i]].size();j++){ Tree::insert(root[i],pre,1,n,lab[ptr[i]][j]); pre=root[i];// D(lab[ptr[i]][j]); E; } } else root[i]=root[i-1]; }// D(Tree::query(root[4],root[5],1,n,1)); E; for(int i=1;i<=n;i++){ int x=relib[i]; int k; scanf("%d",&k);// int rk=Tree::rank(root[pos[x]-1],root[end[x]],1,n,i);// D(rk); E;// if(rk<=k) k++;// D(pos[x]); D(end[x]); E; int ans=Tree::query(root[pos[x]-1],root[end[x]],1,n,k); printf("%d\n",ans); }}
阅读全文
0 0
- BZOJ3439: Kpm的MC密码
- BZOJ3439 KPM的MC密码
- BZOJ3439: Kpm的MC密码
- bzoj3439: Kpm的MC密码
- 【bzoj3439】Kpm的MC密码 trie树+主席树
- bzoj3439: Kpm的MC密码(四种做法)
- 【BZOJ3439】Kpm的MC密码 Trie+dfs序+可持久化线段树
- 【BZOJ3439】Kpm的MC密码,trie树+dfs序+主席树
- [BZOJ 3439]Kpm的MC密码
- bzoj 3439: Kpm的MC密码
- bzoj 3439: Kpm的MC密码
- 3439: Kpm的MC密码 trie+主席树
- BZOJ_P3439 Kpm的MC密码(Trie树+主席树)
- 【BZOJ 3439】Kpm的MC密码 主席树+trie树
- 【BZOJ 3439】Kpm的MC密码 主席树+trie树
- BZOJ 3439 Kpm的MC密码 Trie树+可持久化线段树
- BZOJ 3439 Kpm的MC密码 Trie+可持久化线段树
- [BZOJ]3439: Kpm的MC密码 trie树+主席树(线段树合并)
- VLAN
- Android Service完全解析,关于服务你所需知道的一切(下)
- Extjs 中store proxy传值方式
- Spark RDD算子【四】
- 线段树与树状数组的区别
- BZOJ3439: Kpm的MC密码
- 算法学习记录十一(C++)--->调整数组顺序使奇数前偶数后
- J1708协议
- Buoys Gym
- mac下修改mysql的密码
- Android 屏幕适配攻略(一)
- Ubuntu 下的apt-get/apt 命令详解
- universal-Image-Loader
- iMindMap更新再次来袭,你懂的