[洛谷P1801]黑匣子

[洛谷P1801]黑匣子

一.前言

long long就果然还是就该用cout,没有lld的ll留下了悔恨的眼泪……

链接一放,要看什么对顶堆的走开走开,我只会离散化加权值树状数组……

二.思路

​ 首先吧,这个询问依次递增就友善的一批,然后询问某刻第k位,我们用权值树状数组。首先如果i有,那么在数组中下标为i的位置就打成1,没有就是0,树状数组里面存的是前缀和。那么询问某一个点的前缀和就等效于当前数组中小于等于它的个数。

​ 那么二分一下,毕竟在树状数组中前缀和单调递增……然后就能快速找到想要的点。很慢,但是能过。

​ 但是题目每个的值好像有点大?离散一下,教你做人。sort 一手,以下标代表这个数,在树状数组中是等效的。

还有一些细节看代码吧……没有时间了要睡了

三.CODE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cstring>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
const int MAXN=3000005;
int n,m,to[MAXN];
struct f{
	int num,ls;
	long long h;
}a[MAXN];
bool cmp1(f a,f b){
	return a.h<b.h;
}
bool cmp2(f a,f b){
	return a.num<b.num;
}
int c[MAXN];
void add(int x){
	for(;x<=n;x+=lowbit(x))c[x]++;
}
int get(int x){
	int res=0;
	for(;x;x-=lowbit(x))res+=c[x];
	return res;
}
void solve(int x){
	int l=1,r=n,ans;
	while(l<=r){
		int mid=(l+r)>>1;
		int u=get(mid);
		if(u==x)ans=mid,r=mid-1;
		else if(u<x)l=mid+1;
		else if(u>x)r=mid-1;
	}
	printf("%d\n",a[to[ans]].h);
}
int main(){
	memset(a,0x3f,sizeof(a));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld",&a[i].h);
		a[i].num=i;
	}
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=n;++i){
		a[i].ls=i;
		to[i]=a[i].num;
	}
	sort(a+1,a+n+1,cmp2);
	int cnt=1,j;
	scanf("%d",&j);
	for(int i=1;i<=n;++i){
		add(a[i].ls);
		while(i==j){
			solve(cnt);
			cnt++;
			if(cnt==m+1)return 0;
			scanf("%d",&j);
		}
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/clockwhite/p/13368994.html