可持续化线段树

#include<bits/stdc++.h>

using namespace std;
int cnt;//总共有多少个节点 
struct node
{
	int l,r;//左儿子 右儿子编号 
	int sum;//区间和 
	node(){
		l=r=sum=0;
	}
}z[maxn*logn];

void update(int p)
{
	z[p].sum = z[z[p].l].sum + z[z[p].r].sum;
}

int build(int l,int r)//当前的区间为l~r 是这段区间对应的节点编号 
{
	cnt++;
	int p=cnt;
	if (l==r)
	{
		z[p].sum = a[l];
		return p;
	}
	int m=(l+r)>>1;
	z[p].l = build(l,m);
	z[p].r = build(m+1,r);
	update(p);
	return p;
}

int query(int l,int r,int rt,int nowl,int nowr)
//当前线段树节点编号为rt 对应的区间为l~r 要询问nowl~nowr这段区间的和
{
	if (nowl <= l && r <= nowr) return z[rt].sum;
	int m=(l+r)>>1;
	if (nowl<=m)
	{
		if (m<nowr) return query(l,m,z[rt].l,nowl,nowr) + query(m+1,r,z[rt].r,nowl,nowr);
		else return query(l,m,z[rt].l,nowl,nowr);
	}
	else return query(m+1,r,z[rt].r,nowl,nowr);
} 

int modify(int l,int r,int rt,int p,int v)//返回修改后的新节点编号 
//当前线段树节点编号为rt 对应的区间为l~r 要把a[p]+=v 
{
	cnt++;int q = cnt;//新的节点q用于修改
	z[q] = z[rt]; 
	if (l==r)
	{
		z[q].sum += v;
		return q;
	}
	int m=(l+r)>>1;
	if (p<=m)//在左儿子
		z[q].l = modify(l,m,z[q].l,p,v);
	else 
		z[q].r = modify(m+1,r,z[q].r,p,v);
	update(q);
	return q;
}

int main()
{
	cin >> n;
	for (int i=1;i<=n;i++)
		cin >> a[i];
	cin >> m;
	root[0] = build(1,n);//root[i]代表第i次操作后的根节点是谁
	for (int i=1;i<=m;i++) 
	{
		int opt;
		cin >> opt;
		if (opt==1)
		{
			int p,v;
			cin >> p >> v;
			root[i] = modify(1,n,root[i-1],p,v);
		}
		else
		{
			int k,l,r;
			cin >> k >> l >> r;
			cout << query(1,n,root[k],l,r) << "\n";
			root[i] = root[i-1];
		}
	}
	
	return 0;
}
posted @ 2025-06-21 20:41  Fire_poetry  阅读(6)  评论(0)    收藏  举报