lnk-k

导航

 

简单复盘一下当时卡起一道题,也算树状数组入门题吧(虽然我看tag是线段树,无伤大雅),P1801 黑匣子这里为题面。首先这是一道单点修改单点查询的题目,每次查询时i加1,查询第i小的元素,于是先用t来记录查询次数。首先思路是吧a和u都全部存储起来,由于我们要找第i小的元素,故考虑先进行离散化处理,得到的新数组的下标i加1就是第i小的元素。接着在a数组里进行单点添加操作,先通过Lower bound查询a[i]在新数组里的位置id,然后add(id,a[i]),再来判断此时u[t]是否等于i,如果是就进行查询操作,通过二分找到第i小的元素在新数组里的位置,再进行输出即可得到结果。下面是代码展示。

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+10;

ll c[maxn];

int n;

inline int lowbit(int x){
    return x&-x;
}

void add(int x,int k){
    while(x<=n){
        c[x]+=k;
        x=x+lowbit(x);
    }
}

ll getsum(int x){
    ll res=0;
    while(x>=1){
        res+=c[x];
        x=x-lowbit(x);
    }
    return res;
}


int main(){
    int q,m;
    cin>>q>>m;
    vector<ll>a(q);
    vector<int>u(m);
    for(auto &it:a)cin>>it;
    for(auto &it:u)cin>>it;
    auto all=a;
    sort(all.begin(),all.end());
    all.erase(unique(all.begin(),all.end()),all.end());
    n=all.size();
    int t=0;
    for(int i=1;i<=q;i++){//因为u[i]是1开始所以这里也是从1开始
        int id=lower_bound(all.begin(),all.end(),a[i-1])-all.begin()+1;
        add(id,1);
        while(t<m&&u[t]==i){
            t++;
            int l=1,r=n;
            while(l<r){
                int mid=l+r>>1;
                if(getsum(mid)>=t)r=mid;
                else l=mid+1;
            }
            cout<<all[l-1]<<"\n";
        }
    }
    return 0;
}

第一次写题解喵

posted on 2025-07-28 23:45  1uoan  阅读(4)  评论(0)    收藏  举报