BZOJ 3439: Kpm的MC密码
...(裸trie+主席树 想写离线的 结果维护前面个数特判-1的时候考虑不清 ...维护下后缀和就ojbk了 ......还是太年轻
3439: Kpm的MC密码
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 1013 Solved: 474
[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<len<=300000
-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<len<=300000
#include <bits/stdc++.h> #define N 100005 using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-'0',ch=getchar(); return f*x; } typedef struct node{ int a[26],sum; vector<int>v_; }node; node d[N<<2]; int cnt,root; int csh(){ cnt++;d[cnt].sum=0; for(int i=0;i<26;i++) d[cnt].a[i]=0; return cnt; } void insert(char s[],int tt){ int len=strlen(s);int temp=root; for(int i=len-1;i>=0;i--){ int t=s[i]-'a'; if(d[temp].a[t]==0){ d[temp].a[t]=csh(); } temp=d[temp].a[t]; if(i==0) d[temp].v_.push_back(tt); } } int fp[N],cnt1; void dfs1(int x){ if(d[x].v_.size()!=0){ fp[++cnt1]=x;d[x].sum=1; } for(int i=0;i<26;i++){ if(d[x].a[i]!=0){ dfs1(d[x].a[i]); d[x].sum+=d[d[x].a[i]].sum; } } } typedef struct List{ int l,r,sum; }List; int rt[N],cnt2; List dd[50*N]; void update(int &x,int y,int l,int r,int t){ cnt2++;x=cnt2;dd[x]=dd[y];dd[x].sum++; if(l==r) return ; int mid=(l+r)>>1; if(t<=mid) update(dd[x].l,dd[y].l,l,mid,t); else update(dd[x].r,dd[y].r,mid+1,r,t); } int ans; void querty(int x,int y,int l,int r,int k){ if(l==r){ ans=l;return ; } int mid=(l+r)>>1; if(dd[dd[y].l].sum-dd[dd[x].l].sum>=k) querty(dd[x].l,dd[y].l,l,mid,k); else querty(dd[x].r,dd[y].r,mid+1,r,k-(dd[dd[y].l].sum-dd[dd[x].l].sum)); } char str[N]; int ans1[N],que[N]; int sum1[N]; int main(){ int n;scanf("%d",&n); cnt2=cnt1=cnt=0; root=csh(); for(int i=1;i<=n;i++){ scanf(" %s",str); insert(str,i); } for(int i=1;i<=n;i++) scanf("%d",&que[i]); dfs1(root);int u=0; sum1[0]=0; for(int i=cnt1;i>=1;i--){ u++; sum1[u]=sum1[u-1]+d[fp[i]].v_.size(); } u=0; for(int i=cnt1;i>=1;i--){ u++; for(int j=0;j<d[fp[i]].v_.size();j++){ if(j==0) update(rt[u],rt[u-1],1,n,d[fp[i]].v_[j]); else update(rt[u],rt[u],1,n,d[fp[i]].v_[j]); } for(int j=0;j<d[fp[i]].v_.size();j++){ int tt=d[fp[i]].v_[j]; if(que[tt]>sum1[u]-sum1[u-d[fp[i]].sum]) ans1[tt]=-1; else{ querty(rt[u-d[fp[i]].sum],rt[u],1,n,que[tt]); ans1[tt]=ans; } } } for(int i=1;i<=n;i++) printf("%d\n",ans1[i]); return 0; }