BZOJ3439 Kpm的MC密码(可持久化trie)
将串反过来就变成查询前缀了。考虑建一棵可持久化trie,查询时二分答案,均摊一下复杂度即为O(mlogn)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> #include<vector> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 100010 #define M 300010 int n,cnt=0,root[N],size[N]; vector<int> a[N]; struct data{int ch[26],x; }tree[M<<1]; void ins(int &k,int x,int p) { tree[++cnt]=tree[k],k=cnt;tree[k].x++; if (p==size[x]) return; ins(tree[k].ch[a[x][p]],x,p+1); } int query(int k,int x,int p) { if (!k) return 0; if (p==size[x]) return tree[k].x; return query(tree[k].ch[a[x][p]],x,p+1); } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3439.in","r",stdin); freopen("bzoj3439.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) { char c=getchar(); while (c<'a'||c>'z') c=getchar(); while (c>='a'&&c<='z') a[i].push_back(c-'a'),c=getchar(); root[i]=root[i-1];size[i]=a[i].size(); reverse(a[i].begin(),a[i].end()); ins(root[i],i,0); } for (int i=1;i<=n;i++) { int x=read(); int l=1,r=n,ans=-1; while (l<=r) { int mid=l+r>>1; if (query(root[mid],i,0)>=x) ans=mid,r=mid-1; else l=mid+1; } printf("%d\n",ans); } return 0; }