hdu 4417 Super Mario/树套树

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

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

好像函数式线段树可解吧,可弱弱的沙茶一直没弄懂其精髓敲打只好用树套树暴力碾压了。

额树套树,线段树的每一个节点套一个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 = 100100;
struct SBT{
	int v, s, c;
	SBT *ch[2];
	inline void set(int _v = 0){
		v = _v, c = s = 1;
		ch[0] = ch[1] = null;
	}
	inline void push_up(){
		s = ch[0]->s + ch[1]->s + c;
	}
	inline int cmp(int x) const{
		return v == x ? -1 : x > v;
	}
}*null, stack[Max_N << 3], *ptr[Max_N << 2];
int sz = 0, sum = 0, arr[Max_N];
void init(){
	null = &stack[sz++];
	null->v = null->s = null->c = 0;
}
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, 0), Maintain(x, 1);
}
void insert(SBT* &x, int v){
	if (x == null){
		x = &stack[sz++];
		x->set(v);
	} else {
		x->s++;
		int d = x->cmp(v);
		if (-1 == 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 = 0; x != null;){
		t = x->ch[0]->s;
		if (key < x->v) x = x->ch[0];
		else if (key >= x->v) cur += x->c + t, x = x->ch[1];
	}
	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) >> 1;
	seg_built(lc, l, mid);
	seg_built(rc, mid + 1, 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) >> 1;
	seg_rank(lc, l, mid, x, y, v);
	seg_rank(rc, mid + 1, 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 = 1;
	scanf("%d", &t);
	while (t--){
		sz = 0, init();
		scanf("%d %d", &n, &m);
		printf("Case %d:\n", k++);
		for (i = 1; i <= n; i++) scanf("%d", &arr[i]);
		seg_built(1, 1, n);
		while (m--){
			scanf("%d %d %d", &a, &b, &c);
			sum = 0;
			seg_rank(1, 1, n, a + 1, b + 1, c);
			printf("%d\n", sum);
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值