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<<endl
using 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);
}
}