// 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();
}
}
hdu 4417 求[l,r]区间内小于v的有多少个
最新推荐文章于 2021-07-21 14:44:43 发布
本文介绍了函数式线段树这一高级数据结构的实现方法及其应用。通过具体实例讲解了如何利用函数式线段树解决区间查询问题,并分享了实现过程中的一些心得与体会。
364

被折叠的 条评论
为什么被折叠?



