Codeforces Round #719 (Div. 3) F2 题解(神仙证明+线段树上二分)

题目链接

题目思路

本质上就是利用线段树上二分的思维但是没有用线段树而已

最关键的是如何证明这样的查询次数少于\(6e4\)

由于节点是\(1e5\)

那么这颗线段树的深度最多\(18\)

最坏的情况是深度\(14\)全部占满那么查询的次数就是\(2^{14}-1\)

而最多\(1e4\)次查询下面四层节点最多查询\(4\)

那么最多查询\(4e4+2^{14}-1\)

代码

#include<bits/stdc++.h>
#define debug printf("\n I am here\n");
#define fi first
#define se second
#define pii pair<int,int>
typedef long long ll;
const int maxn=2e3+5,inf=0x3f3f3f3f,mod=1e9+7;
const ll INF=0x3f3f3f3f3f3f3f3f;
using namespace std;
int n,t;
int k;
map<pair<int,int>,int> mp;
int cal(int l,int r){
    if(mp.count({l,r})) return mp[{l,r}];
    printf("? %d %d\n",l,r);
    fflush(stdout);
    int re;
    scanf("%d",&re);
    mp[{l,r}]=r-l+1-re;
    return mp[{l,r}];
}
void query(int l,int r,int k){
    mp[{l,r}]--;
    if(l==r){
        printf("! %d\n",l);
        fflush(stdout);
        return ;
    }
    int mid=(l+r)/2;
    if(cal(l,mid)>=k) query(l,mid,k);
    else query(mid+1,r,k-cal(l,mid));
}
int main(){
    scanf("%d%d",&n,&t);
    while(t--){
        scanf("%d",&k);
        query(1,n,k);
    }
    return 0;
}

posted @ 2021-05-10 15:24  hunxuewangzi  阅读(63)  评论(0)    收藏  举报