题目链接
题意:给一个长度为n的序列,m次询问,问你原序列的总和最大且字典序最小的长度为k的子序列的第pos位元素是多少。
思路:一开始每个长度得最优序列其实是可以构造出来的,但是数组开不了那么大,而且也容易tle,所以一种思路不行换一种思路,我们可以将这m个询问进行排序,由于是离线操作,我们可以通过树状数组来快速构造满足条件的序列,这里简单说一下怎么的序列是最优的,就是尽可能地保留大的数,如果一个数不能全部删完,那么我们优先删除下标靠后的,所以我们排序的时候先按值从大到小排,当值相同时按下标从小到大排。至于第pos位的话用树状数组加二分来查。
#include <bits/stdc++.h>
using namespace std;
#define lowbit(i) ((i)&(-i))
const int maxn=2e5+1;
int n,q,b[maxn],c[maxn],ans[maxn];
struct node{
int num,id;
}a[maxn];
struct cxk{
int k,pos,id;
}s[maxn];
bool cmp(const node &a,const node &b)
{
return a.num==b.num?a.id<b.id:a.num>b.num;
}
bool cmp2(const cxk &x,const cxk &y)
{
return x.k<y.k;
}
void update(int x)
{
while(x<maxn) c[x]++,x+=lowbit(x);
}
int query(int x)
{
int res=0;
while(x>0) res+=c[x],x-=lowbit(x);
return res;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i) scanf("%d",&a[i].num),b[i]=a[i].num,a[i].id=i;
sort(a+1,a+1+n,cmp);
scanf("%d",&q);
for(int i=1;i<=q;++i)
scanf("%d%d",&s[i].k,&s[i].pos),s[i].id=i;
sort(s+1,s+1+q,cmp2);
int k=1;
for(int i=1;i<=q;++i)
{
while(k<=s[i].k) update(a[k].id),k++;
int l=1,r=n;
while(l<r)
{
int mid=(l+r)>>1;
if(query(mid)>=s[i].pos) r=mid;
else l=mid+1;
}
ans[s[i].id]=b[l];
}
for(int i=1;i<=q;++i) printf("%d\n",ans[i]);
}