hdu 4417 求[l,r]区间内小于v的有多少个

本文介绍了函数式线段树这一高级数据结构的实现方法及其应用。通过具体实例讲解了如何利用函数式线段树解决区间查询问题,并分享了实现过程中的一些心得与体会。
//	hdu 4417 求[l,r]区间内小于v的有多少个
//
//	解题思路:
//		
//		函数式线段树.终于见识了一下这个高大上的数据结构
//	当出现更新的时候将前面的线段树完整的保存下来,然后将
//	需要更新的节点复制下来的同时,将其不更新的部分连接到
//	前面一个线段树上.这样最省空间.并且多了一个性质,就是
//	两个线段树之间的对应节点满足加减性质.这样就很好啦~~
//	,记录每个数字出现的次数,再进行加减操作就好啦~~~
//
//	感悟:
//
//		很高大上的结构,看着还是挺简单,但是想法估计有点难
//	并且现在只是会裸地...继续加油吧!FIGHTING!!!

#include <cstring>
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <vector>
#include <queue>
#define For(x,a,b,c) for (int x = a; x <= b; x += c)
#define Ffor(x,a,b,c) for (int x = a; x >= b; x -= c)
#define cls(x,a) memset(x,a,sizeof(x))
using namespace std;
typedef long long ll;

const double PI = acos(-1.0);
const double eps = 1e-9;
const int MAX_N = 1e5 + 8;

const int INF = 1e9 + 7;
const ll MOD = 1e9 + 7;

int N,M;
int a[MAX_N];
int b[MAX_N];

struct node{
	int ls;
	int rs;
	int sum;
};

struct IntravelTree{
	node p[MAX_N * 20];
	int root[MAX_N];

	int Siz;

	void init(){
		Siz = 1;
	}

	int build(int L,int R){
		int rt = Siz++;
		p[rt].sum = 0;

		if (L == R){
			return rt;
		}

		int M = (L + R) >> 1;

		p[rt].ls = build(L,M);
		p[rt].rs = build(M+1,R);
		return rt;
	}

	int update(int rt,int q,int v,int L,int R){
		int nrt = Siz++;
		p[nrt] = p[rt];
		p[nrt].sum += v;
		if (L == R) return nrt;

		int M = (L + R) >> 1;

		if (q <= M)
			p[nrt].ls = update(p[rt].ls,q,v,L,M);
		else 
			p[nrt].rs = update(p[rt].rs,q,v,M+1,R);
		return nrt;
	}

	int query(int rtl,int rtr,int q,int L,int R){
		if (L == R) return p[rtr].sum - p[rtl].sum;

		int res = 0;
		
		int M = (L + R) >> 1;

		if (q <= M){
			res += query(p[rtl].ls,p[rtr].ls,q,L,M);
		}else {
			res += p[p[rtr].ls].sum - p[p[rtl].ls].sum;
			res += query(p[rtl].rs,p[rtr].rs,q,M+1,R);
		}
		return res;
	}


}it;


void input(){

	scanf("%d%d",&N,&M);

	For(i,1,N,1){
		scanf("%d",&a[i]);
		b[i] = a[i];
	}

	sort(b+1,b+N+1);

	int tot = unique(b + 1 , b + N + 1) - b;
	b[tot] = INF;
	

	it.init();

	it.root[0] = it.build(1,tot);

	For(i,1,N,1){
		a[i] = lower_bound(b + 1, b + tot + 1,a[i]) - b ;
		it.root[i] = it.update(it.root[i-1],a[i],1,1,tot);
	}

	//print();

	while(M--){
		int l,r,v;
		scanf("%d%d%d",&l,&r,&v);
		l++,r++;
		int k = upper_bound(b + 1,b + tot + 1, v) - b -1;
		//cout << k << endl;
		int ans = 0;

		if (k > 0){
			ans = it.query(it.root[l-1],it.root[r],k,1,tot);
		}

		printf("%d\n",ans);
	}
}

int main(){
	int t;
	//freopen("1.in","r",stdin);
	//freopen("1.out","w",stdout);
	scanf("%d",&t);
	int kase = 1;
	while(t--){
		printf("Case %d:\n",kase++);
		input();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值