2020牛客NOIP赛前集训营-提高组(第五场)C 经典字符串问题

R e s u l t Result Result

...


H y p e r l i n k Hyperlink Hyperlink

https://ac.nowcoder.com/acm/contest/7613/C


D e s c r i p t i o n Description Description

给定一个长度为 n n n的序列, m m m个询问,求静态区间字典序第 k k k

数据范围: n , m ≤ 1 0 5 n,m\leq 10^5 n,m105


S o l u t i o n Solution Solution

转换成字符串之后排序,得到一个新的 r a n k rank rank,记为 c c c,对 c c c建立主席树,在建立映射数组 a a a,表示这个位置上的数原来对应的数

时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)


C o d e Code Code
#include<cstdio>
#include<cctype>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 100010
#define LL long long
using namespace std;int T[N],sum[N<<5],L[N<<5],R[N<<5],n,q,a[N],b[10],len,c[N],cnt,x,y,z;
struct node{int id,a;string s;}p[N];
inline bool cmp(node x,node y){return x.s<y.s;}
inline LL read()
{
	LL d=1,f=0;char c;
	while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
	while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
	return d*f;
}
inline int build(int l,int r)
{
	int rt=++cnt,mid=l+r>>1;
	if(l==r) {L[rt]=R[rt]=rt;return rt;}
	L[rt]=build(l,mid);
	R[rt]=build(mid+1,r);
	return rt;
}
inline int updata(int pre,int l,int r,int x)
{
	int rt=++cnt,mid=l+r>>1;
	L[rt]=L[pre];R[rt]=R[pre];sum[rt]=sum[pre]+1;
	if(l^r)
	{
		if(x<=mid) L[rt]=updata(L[pre],l,mid,x);
		else R[rt]=updata(R[pre],mid+1,r,x);
	}
	return rt;
}
inline int query(int p,int q,int l,int r,int k)
{
	if(l>=r) return l;
	int x=sum[L[q]]-sum[L[p]],mid=l+r>>1;
	if(x>=k) return query(L[p],L[q],l,mid,k);
	else return query(R[p],R[q],mid+1,r,k-x);
}
signed main()
{
	n=read();q=read();
	for(int i=1;i<=n;i++)
	{
		x=p[i].a=read();p[i].id=i;len=0;
		while(x) b[len++]=x%10,x/=10;
		reverse(b,b+len);
		for(int j=0;j<len;j++) p[i].s+=b[j]+48;
	}
	sort(p+1,p+1+n,cmp);
	for(int i=1;i<=n;i++) c[p[i].id]=i,a[i]=p[i].a;
	T[0]=build(1,n);
	for(int i=1;i<=n;i++) T[i]=updata(T[i-1],1,n,c[i]);
	while(q--)
	{
		x=read();y=read();z=read();
		if(z>y-x+1) {puts("-1");continue;}
		int t=query(T[x-1],T[y],1,n,z);
		printf("%d\n",a[t]);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值