HDU4417 Super Mario 主席树

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - HDU4417


题意概括

  给定一个长度为n的区间,同时给出m个询问,每次询问在区间[l,r]中有多少个数小于或等于k。


题解

  几乎是模板题。

  我们只需要把query函数随便改改就可以了。


代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=100005,S=N*4*20;
int T,n,m,root[N],ls[S],rs[S],sum[S],v[N],ha[N],cnt,total;
void pushup(int rt){
	sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
int build(int le,int ri){
	int rt=++total;
	if (le==ri){
		ls[rt]=rs[rt]=sum[rt]=0;
		return rt;
	}
	int mid=(le+ri)>>1;
	ls[rt]=build(le,mid);
	rs[rt]=build(mid+1,ri);
	pushup(rt);
	return rt;
}
int update(int rt,int le,int ri,int pos){
	int now=++total;
	if (le==ri){
		sum[now]=sum[rt]+1;
		ls[now]=rs[now]=0;
		return now;
	}
	int mid=(le+ri)>>1;
	if (pos<=mid)
		ls[now]=update(ls[rt],le,mid,pos),rs[now]=rs[rt];
	else
		rs[now]=update(rs[rt],mid+1,ri,pos),ls[now]=ls[rt];
	pushup(now);
	return now;
}
int query(int rt1,int rt2,int le,int ri,int val){
	if (ha[ri]<=val)
		return sum[rt2]-sum[rt1];
	if (ha[le]>val)
		return 0;
	int mid=(le+ri)>>1;
	return query(ls[rt1],ls[rt2],le,mid,val)+query(rs[rt1],rs[rt2],mid+1,ri,val);
}
int main(){
	scanf("%d",&T);
	for (int Case=1;Case<=T;Case++){
		printf("Case %d:\n",Case);
		scanf("%d%d",&n,&m);
		for (int i=1;i<=n;i++)
			scanf("%d",&v[i]),ha[i]=v[i];
		sort(ha+1,ha+n+1);
		cnt=1;
		for (int i=2;i<=n;i++)
			if (ha[i]!=ha[i-1])
				ha[++cnt]=ha[i];
		total=0;
		root[0]=build(1,cnt);
		for (int i=1;i<=n;i++){
			v[i]=lower_bound(ha+1,ha+cnt+1,v[i])-ha;
			root[i]=update(root[i-1],1,cnt,v[i]);
		}
		for (int i=1;i<=m;i++){
			int a,b,v;
			scanf("%d%d%d",&a,&b,&v);
			printf("%d\n",query(root[a],root[b+1],1,cnt,v));
		}
	}
	return 0;
} 

  

posted @ 2017-12-12 20:51  zzd233  阅读(276)  评论(0编辑  收藏  举报