#3637 Rollcall 【离线+权值线段树】

版权声明:----------------------------------------转载是ok的,但要附上出处哟 https://blog.csdn.net/qq_43040655/article/details/87362591

描述
初始有一个空集,依次插入N个数Ai。有M次询问Bj,表示询问第Bj个数加入集合后的排名为j的数是多少

输入
第一行是两个整数N,M

接下来一行有N个整数,Ai

接下来一行有M个整数Bj,保证数据合法

输出
M行,回答每个询问

样例输入 [复制]
7 4
9 7 2 8 14 1 8
1 2 6 6
样例输出 [复制]
9
9
7
8

【说明】

第一次询问,当前几何{9},1th=9

第二次询问,当前集合{9,7}的第2=9

第三次询问,当前集合{9,7,2,8,14,1}的第3=7

第四次询问,当前几何{9,7,2,8,14,1}的第4=8

【数据规模】

40%的数据保证 n ≤ 1000

100%的数据保证1≤m≤n≤30000;0≤Ai<2^32

思路:

离线+权值线段树//要开long long。。。

#include<bits/stdc++.h>
#define sf scanf
#define lc (p<<1)
#define rc ((p<<1)|1)
#define int long long
//没开long long见祖宗。。。。
//真没开long long。。。。
//int <=2e31-1 
using namespace std;
const int maxn=3e4+10;
int num[maxn],n,m,ans[maxn];
int sum[maxn<<2],hash[maxn<<1],tot=0;
vector <int> G[maxn];
void change(int p,int l,int r,int k){
	if(l==r){
		++sum[p];return;
	}
	int mid=(l+r)>>1;
	if(k>mid) change(rc,mid+1,r,k);
	else change(lc,l,mid,k);
	sum[p]=sum[lc]+sum[rc];
}
int query(int p,int l,int r,int k){
	if(l==r){
		return hash[l];
	}
	int mid=(l+r)>>1;
	if(k<=sum[lc])return query(lc,l,mid,k);
	else return query(rc,mid+1,r,k-sum[lc]);	
}
signed main(){
	   freopen("rollcall.in","r",stdin);
	   freopen("rollcall.out","w",stdout);
		sf("%lld%lld",&n,&m);
		for(int i=1;i<=n;++i){
			sf("%lld",&num[i]);hash[i]=num[i];
		}
		for(int i=1;i<=m;++i){
			int id;
			sf("%lld",&id);
			G[id].push_back(i);
		}
		sort(hash+1,hash+n+1);
		tot=unique(hash+1,hash+n+1)-hash-1;
		for(int i=1;i<=n;++i){
			int id=lower_bound(hash+1,hash+tot+1,num[i])-hash;
			change(1,1,tot,id);
			for(int j=0;j<G[i].size();++j){
				int k=G[i][j];
				ans[k]=query(1,1,tot,k);
			}
		}
		for(int i=1;i<=m;++i)printf("%lld\n",ans[i]);
	   return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43040655/article/details/87362591
今日推荐