方法一:
记忆化二分,有这么两种二分:、
第一种和线段树的所有区间重叠,的子区间都是
,如果开个桶去记忆化,需要查
次,但可以知道的是被遍历的区间远小于这么多,所以可以去记忆化。
方法二:
将扩大到
的幂次,然后预处理
的幂次的下标
的值
(即对原数组分块)。然后每次二分答案在那个块里面(已经预处理,不需要询问测评姬),接着只要在长度不大与
的块里面二分询问就可以了。找到答案后用树状数组维护
的值
增加的值。
MyCode:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
map<pair<int,int>,int>mp;
void add(int l,int r,int x) {
--mp[{l,r}];
if(l==r) return;
int mid=(l+r)>>1;
if(x<=mid) add(l,mid,x);
else add(mid+1,r,x);
}
int main() {
int n,t,k;
cin>>n>>t;
while(t--) {
cin>>k;
int l=1,r=n,mid,x;
while(l<r) {
mid=(l+r)>>1;
if(!mp.count({l,mid})) {
cout<<"? "<<l<<' '<<mid<<endl;
cin>>x;
mp[{l,mid}]=mid-l+1-x;
}
x=mp[{l,mid}];
if(k<=x) r=mid;
else {
l=mid+1;
k-=x;
}
}
cout<<"! "<<r<<endl;
add(1,n,r);
}
return 0;
} 
京公网安备 11010502036488号