线段树的应用

已知线段树最基本的操作是对于数组的单点修改和区间查询,因此有了以下推广:
之一:对一棵树进行单点修改和子树查询(不论这棵树是否为二叉树,不论节点是否前序遍历编号):
时间复杂度O(logn)即线段树的操作时间,退化成链也一样

原因,线段树查询需要知道l 和r,当节点前序遍历编号时, l就是该节点的编号, 所以我们只需知道r即可完成查询操作。将整棵树进行一遍dfs, 就有r = l + size[l] - 1,其中size[l]为以l为根节点的子树大小(包括l)
而当节点不是前序遍历编号时, 另开两个数组idx[], 和seg_idx[], 即可得到前序遍历编号。idx代表节点u对应的前序遍历编号,seg_idx代表顺序编号下第i个节点对应的原来的树的节点(反对应)

void dfs(int u) {
	siz[u] = 1, idx[u] = ++cnt, seg_idx[cnt] = u;
	for (int v : vec[u]) {
		dfs(v);
		siz[u] += siz[v];
	}
}
ll query(int l, int r, int pos) {
	ll ans = 1ll;
	if (l <= nodes[pos].l && r >= nodes[pos].r) {
		//附上操作
		return ans;
	}
	int mid = nodes[pos].l + nodes[pos].r >> 1;
	if (l <= mid)//操作1
	if (r > mid)//操作2
	return ans;
}
int main(){
	ll ans = query(idx[root], idx[root] + siz[root] - 1, 1);
}

例题
K. Random Numbers

#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define lson pos << 1
#define rson pos << 1 | 1
#define pb push_back
const int mod = 1000000007;
const int N = 1e5 + 10;
struct Seg {
	int l, r;
	ll sum, fac[6];
}nodes[N << 2];
int n;
vector<int> vec[N];
int val[N];

int siz[N], idx[N],seg_idx[N], cnt = 0;
void dfs(int u) {
	siz[u] = 1, idx[u] = ++cnt, seg_idx[cnt] = u;
	for (int v : vec[u]) {
		dfs(v);
		siz[u] += siz[v];
	}
}
int base[6] = { 2, 3, 5, 7, 11, 13 };
void get_factor(int x ,ll p[]) {
	for (int i = 0; i < 6; i++) {
		while (x % base[i] == 0) {
			x /= base[i];
			p[i]++;
		}
	}
}
void update(int pos) {
	nodes[pos].sum = nodes[lson].sum * nodes[rson].sum % mod;
	for (int i = 0; i < 6; i++)
		nodes[pos].fac[i] = (nodes[lson].fac[i] + nodes[rson].fac[i]) % mod;
}
void build(int l, int r, int pos) {
	nodes[pos] = { l, r };
	if (l == r) {
		nodes[pos].l = l;
		nodes[pos].r = r;
		nodes[pos].sum = val[seg_idx[l]];
		get_factor(nodes[pos].sum, nodes[pos].fac);
		return;
	}
	else {
		int mid = l + r >> 1;
		build(l, mid, lson);
		build(mid + 1, r, rson);
		update(pos);
	}
}
void modify(int l, int r,int pos, int u, int x) {
	if (l == r) {
		nodes[pos].sum = nodes[pos].sum * x % mod;
		ll temp[6] = { 0 };
		get_factor(x, temp);
		for (int i = 0; i < 6; i++) {
			nodes[pos].fac[i] = (nodes[pos].fac[i] + temp[i]) % mod;
		}
		return;
	}
	int mid = l + r >> 1;
	if (u <= mid)	modify(l, mid,lson, u, x);
	else modify(mid + 1, r,rson, u, x);
	update(pos);
}
ll ans_array[6];
ll query(int l, int r, int pos) {
	ll ans = 1ll;
	if (l <= nodes[pos].l && r >= nodes[pos].r) {
		for (int i = 0; i < 6; i++) {
			ans_array[i] = (ans_array[i] + nodes[pos].fac[i]) % mod;
		}
		ans = ans * nodes[pos].sum % mod;
		return ans;
	}
	int mid = nodes[pos].l + nodes[pos].r >> 1;
	if (l <= mid)ans = ans * query(l, r, lson) % mod;
	if (r > mid)ans = ans * query(l, r, rson) % mod;
	return ans;
}
void solve() {
	scanf("%d", &n);
	int u, v;
	for (int i = 0; i < n - 1; i++)	scanf("%d%d", &u, &v), vec[u].pb(v);
	for (int i = 0; i < n; i++)	scanf("%d", &val[i]);
	dfs(0);
	build(1, cnt, 1);
	int q;
	scanf("%d", &q);
	while (q--) {
		char str[10];
		scanf("%s", str);
		if (str[0] == 'R') {
			int root;
			scanf("%d", &root);
			for (int i = 0; i < 6; i++)ans_array[i] = 0;
			ll ans = query(idx[root], idx[root] + siz[root] - 1, 1);
			ll ans_f = 1;
			for (int i = 0; i < 6; i++)ans_f = ans_f * (ans_array[i] + 1) % mod;
			printf("%lld %lld\n", ans, ans_f);
		}
		else if (str[0] == 'S') {
			int u, x;
			scanf("%d%d", &u, &x);
			modify(1, cnt,1, idx[u], x);
		}
	}
}
int main() {
	int t = 1;
	while (t--)
		solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值