Description
给定一个 $1$ 到 $n$ 的排列,分别为$a_1,a_2,cdots a_n$。对于每个数,都可以看成一个字 符串,那么 $n$ 个串就可以根据字典序来排序。 比如字符串“123”小于字符串“124”,而字符串“123”的字典序大于字符串“12”。 现在给出 $q$ 个询问,每个询问的格式形如 $l,r,k$,对于每个询问都需要回答在区 间 $[l,r]$ 中的第 $k$ 小字典序是哪个数
Solution
给出一些字符串,求在给定区间内字典序第k小
先对所有字符串排序
再套主席树板子
可惜不能用itoa和atoi,要使用sprintf和sscanf代替
#include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> using namespace std; int n,q,a[100005],id[100005],root[100005],cnt,rk[100005]; struct Node { char str[20]; bool operator < (const Node &z)const { return strcmp(str,z.str)<0; } }node[100005]; struct Seg { int l,r,val; }tree[10000005]; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } int build(int l,int r) { int k=++cnt; if(l==r) { return k; } int mid=l+r>>1; tree[k].l=build(l,mid); tree[k].r=build(mid+1,r); return k; } int update(int i,int l,int r,int pos) { int k=++cnt; tree[k].l=tree[i].l; tree[k].r=tree[i].r; tree[k].val=tree[i].val+1; if(l==r) { return k; } int mid=l+r>>1; if(pos<=mid) { tree[k].l=update(tree[i].l,l,mid,pos); } if(pos>mid) { tree[k].r=update(tree[i].r,mid+1,r,pos); } return k; } int query(int u,int v,int l,int r,int val) { if(l==r) { return l; } int k=tree[tree[v].l].val-tree[tree[u].l].val,mid=l+r>>1; if(val<=k) { return query(tree[u].l,tree[v].l,l,mid,val); } if(val>k) { return query(tree[u].r,tree[v].r,mid+1,r,val-k); } } int main() { n=read(); q=read(); for(int i=1;i<=n;i++) { a[i]=read(); } for(int i=1;i<=n;i++) { sprintf(node[i].str,"%d",a[i]); } sort(node+1,node+n+1); for(int i=1;i<=n;i++) { int x; sscanf(node[i].str,"%d",&x); id[x]=i; rk[i]=x; } root[0]=build(1,n); for(int i=1;i<=n;i++) { root[i]=update(root[i-1],1,n,id[a[i]]); } for(int i=1;i<=q;i++) { int L=read(),R=read(),K=read(); if(R-L+1<K) { puts("-1"); } else { printf("%lld ",rk[query(root[L-1],root[R],1,n,K)]); } } return 0; }