原题链接:http://acm.hdu.edu.cn/showproblem.php?pid=4417

题意很简单,给定一个序列求一个区间 [L, R,]中小于等于H的元素的个数。

好像函数式线段树可解吧,可弱弱的沙茶一直没弄懂其精髓,只好用树套树暴力碾压了hdu 4417 Super Mario/树套树-LMLPHP

额树套树,线段树的每一个节点套一个sb树。

当查询[l,r]区间中的值小于等于H的个数,先用线段树找到相应的区间,

然后再查询该区间下对应的平衡树中小于等于H的个数,累加即可。

一直以为会超时,结果400+ms就过了,数据应该很弱吧(自己对拍了一组(N,M)10w规模的跑了2s多o(╯□╰)o)。

 #include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define lc root<<1
#define rc root<<1|1
const int Max_N = ;
struct SBT{
int v, s, c;
SBT *ch[];
inline void set(int _v = ){
v = _v, c = s = ;
ch[] = ch[] = null;
}
inline void push_up(){
s = ch[]->s + ch[]->s + c;
}
inline int cmp(int x) const{
return v == x ? - : x > v;
}
}*null, stack[Max_N << ], *ptr[Max_N << ];
int sz = , sum = , arr[Max_N];
void init(){
null = &stack[sz++];
null->v = null->s = null->c = ;
}
inline void rotate(SBT* &x, int d){
SBT *k = x->ch[!d];
x->ch[!d] = k->ch[d];
k->ch[d] = x;
k->s = x->s;;
x->push_up();
x = k;
}
void Maintain(SBT* &x, int d){
if (x->ch[d] == null) return;
if (x->ch[d]->ch[d]->s > x->ch[!d]->s){
rotate(x, !d);
} else if (x->ch[d]->ch[!d]->s > x->ch[d]->s){
rotate(x->ch[d], d), rotate(x, !d);
} else {
return;
}
Maintain(x, ), Maintain(x, );
}
void insert(SBT* &x, int v){
if (x == null){
x = &stack[sz++];
x->set(v);
} else {
x->s++;
int d = x->cmp(v);
if (- == d){
x->c++;
return;
}
insert(x->ch[d], v);
x->push_up();
Maintain(x, d);
}
}
int sbt_rank(SBT *x, int key){
int t, cur;
for (t = cur = ; x != null;){
t = x->ch[]->s;
if (key < x->v) x = x->ch[];
else if (key >= x->v) cur += x->c + t, x = x->ch[];
}
return cur;
}
void seg_built(int root, int l, int r){
ptr[root] = null;
for (int i = l; i <= r; i++) insert(ptr[root], arr[i]);
if (l == r) return;
int mid = (l + r) >> ;
seg_built(lc, l, mid);
seg_built(rc, mid + , r);
}
void seg_rank(int root, int l, int r, int x, int y, int v){
if (x > r || y < l) return;
if (x <= l && y >= r){
sum += sbt_rank(ptr[root], v);
return;
}
int mid = (l + r) >> ;
seg_rank(lc, l, mid, x, y, v);
seg_rank(rc, mid + , r, x, y, v);
}
int main(){
#ifdef LOCAL
freopen("in.txt", "r", stdin);
freopen("out.txt", "w+", stdout);
#endif
int i, t, n, m, a, b, c, k = ;
scanf("%d", &t);
while (t--){
sz = , init();
scanf("%d %d", &n, &m);
printf("Case %d:\n", k++);
for (i = ; i <= n; i++) scanf("%d", &arr[i]);
seg_built(, , n);
while (m--){
scanf("%d %d %d", &a, &b, &c);
sum = ;
seg_rank(, , n, a + , b + , c);
printf("%d\n", sum);
}
}
return ;
}
05-11 16:27