[洛谷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
",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;
}