分析:离线线段树,把所有询问离线读入,然后按H从小到大排序。对于所有结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,最后就是一个区间求和。这题貌似也可以用划分树,树状数组等方法做。
#include<iostream>
#include<algorithm>
using namespace std;
#define N 100005
struct Tree
{
int left,right,cnt;
} TREE[N<<2];
struct Query
{
int l,r,h,id;
bool operator<(const Query& q)const
{
return h<q.h;
}
} query[N];
struct Node
{
int pos,val;
bool operator<(const Node& n)const
{
return val<n.val;
}
} node[N];
void Build(int root,int l,int r)
{
int m;
TREE[root].cnt=0;
TREE[root].left=l;
TREE[root].right=r;
if(l==r) return ;
m=(l+r)>>1;
Build(root<<1,l,m); //左子树
Build((root<<1)|1,m+1,r); //右子树
}
void Update(int root,int pos)
{
int m;
TREE[root].cnt++;
if(TREE[root].left==TREE[root].right) return ;
m=(TREE[root].left+TREE[root].right)>>1;
if(pos<=m) Update(root<<1,pos); //左边
else Update((root<<1)|1,pos); //右边
}
int QUERY(int root,int l,int r)
{
int m;
if(TREE[root].left==l && TREE[root].right==r)
return TREE[root].cnt;
m=(TREE[root].left+TREE[root].right)>>1;
if(r<=m) return QUERY(root<<1,l,r); //左边
else if(l>m) return QUERY((root<<1)|1,l,r); //右边
else return QUERY(root<<1,l,m)+QUERY((root<<1)|1,m+1,r); //中间
}
int ans[N];
int main()
{
int t,T,n,q,i,j;
ios::sync_with_stdio(false);
cin>>T;
t=0;
while(T--)
{
cin>>n>>q;
for(i=0;i<n;i++)
{
cin>>node[i].val;
node[i].pos=i+1;
}
for(i=0;i<q;i++)
{
query[i].id=i;
cin>>query[i].l>>query[i].r>>query[i].h;
}
sort(node,node+n);
sort(query,query+q);
Build(1,1,n);
cout<<"Case "<<++t<<":"<<endl;
for(i=0,j=0;i<q;i++)
{
while(j<n && node[j].val<=query[i].h)
{
Update(1,node[j].pos);
j++;
}
ans[query[i].id]=QUERY(1,query[i].l+1,query[i].r+1);
}
for(i=0;i<q;i++)
cout<<ans[i]<<endl;
}
return 0;
}
HDU ACM 4417 Super Mario 离线线段树
原文地址:http://blog.csdn.net/a809146548/article/details/46289375