标记永久化 简易模板两个版本的写法

#include <bits/stdc++.h>

using namespace std;

#define pb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
//标记永久化 即每次区间更新和查询 不去用pushdown更新子区间 每次更新不去用pushup维护父节点
//在树套树 和 主席树区间修改的时候有比较大的用处 有效降低时间复杂度

ll tag[N],tree[N];//tag表示当前区间所有位置都更新的值 tree表示当前区间除了tag之外更新过的值
//相当于把答案分成两部分来维护 由两部分共同获得

//建树是一致的不变
//其实对应有两种写区别在 query函数具体想怎么写
//版本一
void modify(int rt,int l,int r,int L,int R,ll v) {
	tree[rt] += (min(R,r) - max(L,l) + 1) * v;
	if(l >= L && r <= R) {
		tag[rt] += v; return ;
	}
	int mid = (l + r) >> 1;
	if(L <= mid) modify(lson,1,mid,L,R,v);
	if(R > mid) modify(rson,mid+1,r,L,R,v);
	//注意不需要pushup
}
ll query(int rt,int l,int r,int L,int R,ll tg) {//这种写法对应有个tg
	if(l >= L && r <= R) {
		return tree[rt] + (r - l + 1) * tg;//这个没有用到自己的tag
	}
	int mid = (l + r) >> 1;
	ll ans = 0;
	if(L <= mid) ans += query(lson,l,mid,L,R,tg + tag[rt]);//这里的tag只维护了所有祖先包括父亲的值 因此具有正确性
	if(R > mid) ans += query(rson,mid+1,r,L,R,tg + tag[rt]);
	return ans;
}

//版本二
void modify(int rt,int l,int r,int L,int R,ll v) {
	if(l >= L && r <= R) {//完全包含 修改tag
		tag[rt] += v; return ;
	}
	tree[rt] += (min(R,r) - max(L,l) + 1) * v;//不完全包含修改tree
	int mid = (l + r) >> 1;
	if(L <= mid) modify(lson,l,mid,L,R,v);
	if(R > mid) modify(rson,mid+1,r,L,R,V);
}
ll query(int rt,int l,int r,int L,int R) {
	if(l >= L && r <= R) {
		return sum[rt] + (r - l + 1) * tag[rt];//这个用到了自己的tag
	}
	int mid = (l + r) >> 1;
	ll ans = (min(R,r) - max(L,r) + 1) * tag[rt];//当前节点的tag贡献 因为这个需要累加 又因为tree每次遇到区间都更新 多以不用加
	if(L <= mid) ans += query(lson,l,mid,L,R);
	if(R > mid) ans += query(rson,mid+1,r,L,R);
	return ans;
}

int main() {

	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值