HDU ACM 4417 Super Mario 离线线段树

分析:离线线段树,把所有询问离线读入,然后按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;      
}


你可能感兴趣的:(编程,C++,c,算法,ACM)