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的關係就好。
其實離線搞更方便一些,也不用可持久化。。
上代碼c++
#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; }