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);    }}
原创粉丝点击