思路就是删除k个数,之后查询第x个数就等于查询第x+k个数,所以只需要记录删除数个数。记录前缀和。之后使用单调队列求最值,以二分求第x个元素
这里单调队列没问题,不需要看,就请大佬帮我看看之前的二分怎么错了,感激不尽!
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int T,m,n,a[N],len,s[N],q[N],l,r;
//s[]前缀和 a[]最后一个数字 q单调队列 len目前删除的个数
int query(int x){
x+=len;
int t=lower_bound(s+1,s+n+1,x)-s;
return s[t]==x?a[t]:a[t]-s[t]+x;
}
上面是ac的,是使用lowerbound找出第一个大于等于x的数字,之后通过运算求解查询的数大小是啥
以下是错的query函数(用这个70分),是手写二分找出小于等于x但是最大的k(s[k]<=x)
int query(int x){
x+=len;
int l=1,r=n;
while(l<r){
int mid=l+r+1>>1;
if(s[mid]<=x) l=mid;
else r=mid-1;
}
return s[l]==x?a[l]:x-s[l];
}
signed main(){
scanf("%lld%lld",&T,&m);int opt,x;
l=0,r=-1;
while(m--){
scanf("%lld",&opt);
if(opt==1){
scanf("%lld",&x);
a[++n]=x;
s[n]=s[n-1]+a[n];
while(l<=r&&a[q[r]]<=a[n]) r--;
q[++r]=n;
}
else if(opt==2){
scanf("%lld",&x),len+=x;
while(l<=r&&s[q[l]]<=len) l++;
}
else if(opt==3) scanf("%lld",&x),printf("%lld\n",query(x));
else printf("%lld\n",a[q[l]]);
}
return 0;
}
有时候自己手写的二分就是会出现点问题,非常希望能解决这一点!