D Optimal Subsequences
http://codeforces.com/contest/1227/problem/D2
显然,每次求的k一定是这个序列从大到小排序后前k大的元素。
考虑如何做才能使其字典序最小。我们设p为第k大的元素。
首先,这k个数是确定的。
其次,对于比p大的所有元素,他们是必须选的。
所以,欲使这个序列字典序最小,其实就是让所有p出现的位置
尽量靠前。
那做法就很显然了:先离散化,搞出来一个相对排名,用主席树
维护相对排名。每次查询,二分答案,check就查一下root[1]到
root[mid]中权值排名大于p的排名+min(p的上限个数,root[1]
到root[mid]中p的出现次数)和pos的关系就好。
其实离线搞更方便一些,也不用可持久化。。
上代码
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
I read(int &res){
res=0;re g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch=='-')g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
struct P{
int w,id,v;
friend bool operator < (P x,P y){
return x.w>y.w;
}
}p[202000];
struct Tree{
int lc,rc,w;
}t[6060000];
#define L t[k].lc
#define R t[k].rc
int n,m,tot,X,Y,sum,pos,lim,a[202000],b[202000],f[202000],len[202000],root[202000];
I modi(int &k,int k1,int l,int r,int x){
k=++tot;
L=t[k1].lc;R=t[k1].rc;t[k].w=t[k1].w;
if(l==r){
t[k].w++;
return;
}
re mid=(l+r)>>1;
if(x<=mid)modi(L,t[k1].lc,l,mid,x);
else modi(R,t[k1].rc,mid+1,r,x);
t[k].w=t[L].w+t[R].w;
}
IN ques(int k,int l,int r,int x,int y){
if(x>r||y<l)return 0;
if(x<=l&&r<=y)return t[k].w;
re mid=(l+r)>>1;
return ques(L,l,mid,x,y)+ques(R,mid+1,r,x,y);
}
IN divided(int x,int y){
if(x==y)return x;
re mid=(x+y)>>1;
//cout<<ques(root[mid],1,sum,1,pos)<<"!"<<endl;
if(ques(root[mid],1,sum,1,pos-1)+min(ques(root[mid],1,sum,pos,pos),lim)>=Y)y=mid;
else x=mid+1;
return divided(x,y);
}
int main(){
read(n);
F(i,1,n){
read(a[i]);
p[i].w=a[i];
p[i].id=i;
}
sort(p+1,p+1+n);
m=0;
p[0].w=p[1].w+1;
f[0]=0;
F(i,1,n){
if(p[i].w!=p[i-1].w)m++,f[m]=i;
b[p[i].id]=m;
p[i].v=m;
}
tot=0;
sum=m;
//cout<<sum<<endl;
F(i,1,n){
modi(root[i],root[i-1],1,sum,b[i]);
}
read(m);
while(m--){
read(X);read(Y);
pos=p[X].v;lim=X-f[pos]+1;
//cout<<pos<<" ";
int P=divided(1,n);
//cout<<P<<" ";
cout<<a[P]<<endl;
}
return 0;
}