题目链接:https://ac.nowcoder.com/acm/contest/275/E
题意:给定一个序列a[1,n],有多次询问,每次查询给出 (l,r,x),表示查询区间a[l,r]里小于等于k的元素的个数。
解析:如果题目是强制在线操作,那这就是主席树的模板题(我只会套模板)。但此题不强制在在线,那么可以用树状数组离线操作(过程见代码),解法算是比较简单,但是我一个不经常用bit的菜逼也是没想到。
树状数组代码(123ms):
#include
using namespace std;
const int MAXN=1e5+5;
int n,m,bit[MAXN],ans[MAXN];
struct Num{
int x,id;
bool operator<(const Num& obj)const
{
return x0){
res+=bit[i];i-=lowbit(i);
}
return res;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i].x);
a[i].id=i;
}
sort(a+1,a+1+n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].k);
q[i].id=i;
}
sort(q+1,q+1+m);
int it=1;
for(int i=1;i<=m;i++)
{
while(a[it].x<=q[i].k&&it<=n){
add(a[it].id);it++;
}
ans[q[i].id]=sum(q[i].r)-sum(q[i].l-1);
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
return 0;
}
代码模板来自:https://blog.csdn.net/qq_37685156/article/details/80364092
主席树模板代码(255ms):
#include
using namespace std;
const int maxn=1e5+100;
vector v;
int n,m,a[maxn],rt[maxn],tot;
struct node
{
int l,r,sum;
}T[maxn*20];
int getid(int x)
{
return lower_bound(v.begin(),v.end(),x)-v.begin()+1;
}
void build(int &o,int l,int r)
{
o=++tot;
T[o].sum=0;
if(l==r) return;
int mid=(l+r)>>1;
build(T[o].l,l,mid);
build(T[o].r,mid+1,r);
}
void update(int l,int r,int &now,int last,int k)
{
T[++tot]=T[last];
now=tot;
T[now].sum++;
if(l==r) return;
int mid=(l+r)>>1;
if(k<=mid) update(l,mid,T[now].l,T[last].l,k);
else update(mid+1,r,T[now].r,T[last].r,k);
}
int query(int l,int r,int x,int y,int k)
{
if(l==r) return T[y].sum-T[x].sum;
int mid=(l+r)>>1;
if(k<=mid) return query(l,mid,T[x].l,T[y].l,k);
else
{
int ret=0;
ret+=T[T[y].l].sum-T[T[x].l].sum;
ret+=query(mid+1,r,T[x].r,T[y].r,k);
return ret;
}
}
int main()
{
v.clear();
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
v.push_back(a[i]);
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
build(rt[0],1,n);
for(int i=1;i<=n;i++)
update(1,n,rt[i],rt[i-1],getid(a[i]));
for(int i=1;i<=m;i++)
{
int l,r,h;
scanf("%d%d%d",&l,&r,&h);
//l++,r++;//本题下标从1开始
int k=upper_bound(v.begin(),v.end(),h)-v.begin();//v中有k个元素小于等于h
//upper的返回值是指向键值<=key的最后一个元素的后一个元素。
if(!k)
printf("0\n");
else
printf("%d\n",query(1,n,rt[l-1],rt[r],k));
}
return 0;
}