动态开点线段树

普通线段树使用数组下标来表示左右儿子,即完全二叉树的方法。

动态开点线段树:与普通线段树相比,用指针表示左右儿子(类似普通二叉树)。

用于数据范围大但是节点利用率低的情况。

从效果上看有点像离散化。

题目:P5459

该题使用线段树时,会发现根节点范围包括了整个值域,但是实际上只有n个叶子节点有记录值。因此使用动态开点来避免大量无用空间。

定义:(由于仅有单点修改,无需懒标记)

struct node{
	int lc, rc;
	ll data;
}t[MAXN << 8];

单点修改:

void pushup(int p){
	t[p].data = t[t[p].lc].data + t[t[p].rc].data;
}
void insert(int p, ll l, ll r, ll num){
	if(l == r){
		t[p].data++;
		return ;
	}
	ll mid = (l + r) >> 1;
	if(num <= mid){
		if(t[p].lc == 0){
			tot++;
			t[p].lc = tot;
		}
		insert(t[p].lc, l, mid, num);
	}
	else{
		if(t[p].rc == 0){
			tot++;
			t[p].rc = tot;
		}
		insert(t[p].rc, mid + 1, r, num);
	}
	pushup(p);
}

区间求和:

ll qsum(int p, ll l, ll r, ll x, ll y){
	if(p == 0) return 0;
	if(x <= l && r <= y){
		return t[p].data;
	}
	ll res = 0;
	ll mid = (l + r) >> 1;
	if(mid >= x) res += qsum(t[p].lc, l, mid, x, y);
	if(y >= mid + 1) res += qsum(t[p].rc, mid + 1, r, x, y);
	return res;
	
}

完整代码:

#include <bits/stdc++.h>
#define MAXN 100005
#define MAXM 10000000000
#define ll long long
using namespace std;
struct node{
	int lc, rc;
	ll data;
}t[MAXN << 8];
int tot;
int n, L, R;
ll pre[MAXN];
void pushup(int p){
	t[p].data = t[t[p].lc].data + t[t[p].rc].data;
}
void insert(int p, ll l, ll r, ll num){
	if(l == r){
		t[p].data++;
		return ;
	}
	ll mid = (l + r) >> 1;
	if(num <= mid){
		if(t[p].lc == 0){
			tot++;
			t[p].lc = tot;
		}
		insert(t[p].lc, l, mid, num);
	}
	else{
		if(t[p].rc == 0){
			tot++;
			t[p].rc = tot;
		}
		insert(t[p].rc, mid + 1, r, num);
	}
	pushup(p);
}
ll qsum(int p, ll l, ll r, ll x, ll y){
	if(p == 0) return 0;
	if(x <= l && r <= y){
		return t[p].data;
	}
	ll res = 0;
	ll mid = (l + r) >> 1;
	if(mid >= x) res += qsum(t[p].lc, l, mid, x, y);
	if(y >= mid + 1) res += qsum(t[p].rc, mid + 1, r, x, y);
	return res;
	
}
int main(){
	scanf("%d%d%d", &n, &L, &R);
	ll a = 0;
	for(int i = 1; i <= n; i++){
		scanf("%lld", &a);
		pre[i] = pre[i - 1] + a;
	}
	ll ans = 0;
	insert(1, -MAXM, MAXM, 0);
	for(int i = 1; i <= n; i++){
		ans += qsum(1, -MAXM, MAXM, pre[i] - R, pre[i] - L);
		insert(1, -MAXM, MAXM, pre[i]);
	}
	printf("%lld", ans);
	return 0;
}
posted @ 2025-06-24 19:00  LIGHTB  阅读(242)  评论(0)    收藏  举报