简单复盘一下当时卡起一道题,也算树状数组入门题吧(虽然我看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;
}
第一次写题解喵
浙公网安备 33010602011771号